aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Gottfried <sebastiangottfried@web.de>2016-10-07 15:26:06 (GMT)
committerSebastian Gottfried <sebastiangottfried@web.de>2016-10-07 15:26:06 (GMT)
commite06b1c086ba375e27f859f56de0f423f3bedece9 (patch)
treed9773bfde87db33ffff53aca405fa94a1dafaad0
parent8cecca6d52387106a2fab707f5bc09993057ecd3 (diff)
Qt5: Fix The X11 Helper
Required for detecting the current keyboard layout under X11.
-rw-r--r--src/CMakeLists.txt20
-rw-r--r--src/x11_helper.cpp478
-rw-r--r--src/x11_helper.h310
3 files changed, 468 insertions, 340 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c9bcf55..d770f30 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -5,7 +5,10 @@ ecm_setup_version(${KDE_APPLICATIONS_VERSION}
)
find_package(X11)
-# macro_log_feature(X11_Xkbfile_FOUND "libxkbfile" "X Keyboard Extension" "http://www.x.org/wiki/XKB" FALSE "" "Support for keyboard layout auto-detection in KTouch")
+add_feature_info("X11-Xkbfile" X11_Xkbfile_FOUND "required for automatic keyboard layout detection")
+
+find_package(XCB OPTIONAL_COMPONENTS XCB XKB)
+add_feature_info("XCB-XKB" XCB_XKB_FOUND "required for automatic keyboard layout detection")
ecm_optional_add_subdirectory(qml)
ecm_optional_add_subdirectory(schemata)
@@ -96,13 +99,15 @@ qt5_wrap_ui(ktouch_SRCS
ui/customlessoneditordialog.ui
)
-if (X11_Xkbfile_FOUND)
+set (KTOUCH_BUILD_WITH_X11 X11_Xkbfile_FOUND AND XCB_XKB_FOUND AND XCB_FOUND)
+
+if (KTOUCH_BUILD_WITH_X11)
add_definitions(-DKTOUCH_BUILD_WITH_X11)
include_directories(${X11_Xkbfile_INCLUDE_PATH})
set(ktouch_SRCS ${ktouch_SRCS} x11_helper.cpp)
-else (X11_Xkbfile_FOUND)
+else (KTOUCH_BUILD_WITH_X11)
set(ktouch_SRCS ${ktouch_SRCS} keyboardlayoutmenu.cpp)
-endif (X11_Xkbfile_FOUND)
+endif (KTOUCH_BUILD_WITH_X11)
kconfig_add_kcfg_files(ktouch_SRCS preferences.kcfgc)
@@ -110,9 +115,10 @@ add_executable(ktouch ${ktouch_SRCS})
set(ktouch_X11_DEPS "")
-if (X11_Xkbfile_FOUND)
- set(ktouch_X11_DEPS ${X11_Xkbfile_LIB} ${X11_LIBRARIES})
-endif (X11_Xkbfile_FOUND)
+if (KTOUCH_BUILD_WITH_X11)
+ set(ktouch_X11_DEPS ${X11_Xkbfile_LIB} ${X11_LIBRARIES} XCB::XCB XCB::XKB)
+endif (KTOUCH_BUILD_WITH_X11)
+
#uncomment this if oxygen icons for ktouch are available
target_link_libraries(ktouch
diff --git a/src/x11_helper.cpp b/src/x11_helper.cpp
index 2f9972e..9e90136 100644
--- a/src/x11_helper.cpp
+++ b/src/x11_helper.cpp
@@ -18,22 +18,35 @@
#include "x11_helper.h"
+#define explicit explicit_is_keyword_in_cpp
+#include <xcb/xkb.h>
+#undef explicit
+
+
#include <QX11Info>
+#include <QCoreApplication>
+#include <QDebug>
#include <X11/X.h>
+#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/XKBlib.h>
#include <X11/extensions/XKBrules.h>
+#include <xcb/xcb.h>
#include <fixx11h.h>
-
// more information about the limit https://bugs.freedesktop.org/show_bug.cgi?id=19501
-int X11Helper::MAX_GROUP_COUNT = 4;
-const char* X11Helper::LEFT_VARIANT_STR = "(";
-const char* X11Helper::RIGHT_VARIANT_STR = ")";
+const int X11Helper::MAX_GROUP_COUNT = 4;
+const int X11Helper::ARTIFICIAL_GROUP_LIMIT_COUNT = 8;
+
+const char X11Helper::LEFT_VARIANT_STR[] = "(";
+const char X11Helper::RIGHT_VARIANT_STR[] = ")";
bool X11Helper::xkbSupported(int* xkbOpcode)
{
+ if (!QX11Info::isPlatformX11()) {
+ return false;
+ }
// Verify the Xlib has matching XKB extension.
int major = XkbMajorVersion;
@@ -58,7 +71,7 @@ bool X11Helper::xkbSupported(int* xkbOpcode)
}
if( xkbOpcode != NULL ) {
- *xkbOpcode = xkb_opcode;
+ *xkbOpcode = xkb_opcode;
}
return true;
@@ -66,79 +79,82 @@ bool X11Helper::xkbSupported(int* xkbOpcode)
void X11Helper::switchToNextLayout()
{
- int size = getLayoutsList().size(); //TODO: could optimize a bit as we don't need the layouts - just count
- int group = (X11Helper::getGroup() + 1) % size;
- X11Helper::setGroup(group);
+ int size = getLayoutsList().size(); //TODO: could optimize a bit as we don't need the layouts - just count
+ int group = (X11Helper::getGroup() + 1) % size;
+ X11Helper::setGroup(group);
}
void X11Helper::scrollLayouts(int delta)
{
- int size = getLayoutsList().size(); //TODO: could optimize a bit as we don't need the layouts - just count
- int group = X11Helper::getGroup() + delta;
- group = group < 0 ? size - ((-group) % size) : group % size;
+ int size = getLayoutsList().size(); //TODO: could optimize a bit as we don't need the layouts - just count
+ int group = X11Helper::getGroup() + delta;
+ group = group < 0 ? size - ((-group) % size) : group % size;
- X11Helper::setGroup(group);
+ X11Helper::setGroup(group);
}
QStringList X11Helper::getLayoutsListAsString(const QList<LayoutUnit>& layoutsList)
{
- QStringList stringList;
- foreach(const LayoutUnit& layoutUnit, layoutsList) {
- stringList << layoutUnit.toString();
- }
- return stringList;
+ QStringList stringList;
+ foreach(const LayoutUnit& layoutUnit, layoutsList) {
+ stringList << layoutUnit.toString();
+ }
+ return stringList;
}
bool X11Helper::setLayout(const LayoutUnit& layout)
{
- QList<LayoutUnit> currentLayouts = getLayoutsList();
- int idx = currentLayouts.indexOf(layout);
- if( idx == -1 || idx >= X11Helper::MAX_GROUP_COUNT ) {
- qWarning() << "Layout" << layout.toString() << "is not found in current layout list"
- << getLayoutsListAsString(currentLayouts);
- return false;
- }
-
- return X11Helper::setGroup((unsigned int)idx);
+ QList<LayoutUnit> currentLayouts = getLayoutsList();
+ int idx = currentLayouts.indexOf(layout);
+ if( idx == -1 || idx >= X11Helper::MAX_GROUP_COUNT ) {
+ qWarning() << "Layout" << layout.toString() << "is not found in current layout list"
+ << getLayoutsListAsString(currentLayouts);
+ return false;
+ }
+
+ return X11Helper::setGroup((unsigned int)idx);
}
bool X11Helper::setDefaultLayout() {
- return X11Helper::setGroup(0);
+ return X11Helper::setGroup(0);
}
bool X11Helper::isDefaultLayout() {
- return X11Helper::getGroup() == 0;
+ return X11Helper::getGroup() == 0;
}
LayoutUnit X11Helper::getCurrentLayout()
{
- QList<LayoutUnit> currentLayouts = getLayoutsList();
- unsigned int group = X11Helper::getGroup();
- if( group < (unsigned int)currentLayouts.size() )
- return currentLayouts[group];
-
- qWarning() << "Current group number" << group << "is outside of current layout list" <<
- getLayoutsListAsString(currentLayouts);
- return LayoutUnit();
+ if (!QX11Info::isPlatformX11()) {
+ return LayoutUnit();
+ }
+ QList<LayoutUnit> currentLayouts = getLayoutsList();
+ unsigned int group = X11Helper::getGroup();
+ if( group < (unsigned int)currentLayouts.size() )
+ return currentLayouts[group];
+
+ qWarning() << "Current group number" << group << "is outside of current layout list" <<
+ getLayoutsListAsString(currentLayouts);
+ return LayoutUnit();
}
LayoutSet X11Helper::getCurrentLayouts()
{
- LayoutSet layoutSet;
+ LayoutSet layoutSet;
- QList<LayoutUnit> currentLayouts = getLayoutsList();
- layoutSet.layouts = currentLayouts;
+ QList<LayoutUnit> currentLayouts = getLayoutsList();
+ layoutSet.layouts = currentLayouts;
- unsigned int group = X11Helper::getGroup();
- if( group < (unsigned int)currentLayouts.size() ) {
- layoutSet.currentLayout = currentLayouts[group];
- }
- else {
- qWarning() << "Current group number" << group << "is outside of current layout list" << getLayoutsListAsString(currentLayouts);
- layoutSet.currentLayout = LayoutUnit();
- }
+ unsigned int group = X11Helper::getGroup();
+ if( group < (unsigned int)currentLayouts.size() ) {
+ layoutSet.currentLayout = currentLayouts[group];
+ }
+ else {
+ qWarning() << "Current group number" << group << "is outside of current layout list" << getLayoutsListAsString(currentLayouts);
+ layoutSet.currentLayout = LayoutUnit();
+ }
- return layoutSet;
+ return layoutSet;
}
@@ -151,251 +167,285 @@ LayoutSet X11Helper::getCurrentLayouts()
QList<LayoutUnit> X11Helper::getLayoutsList()
{
- XkbConfig xkbConfig;
- QList<LayoutUnit> layouts;
- if( X11Helper::getGroupNames(QX11Info::display(), &xkbConfig, X11Helper::LAYOUTS_ONLY) ) {
- for(int i=0; i<xkbConfig.layouts.size(); i++) {
- QString layout(xkbConfig.layouts[i]);
- QString variant;
- if( i<xkbConfig.variants.size() && ! xkbConfig.variants[i].isEmpty() ) {
- variant = xkbConfig.variants[i];
- }
- layouts << LayoutUnit(layout, variant);
- }
- // if there are layouts with same map name add numbers to display name
+ if (!QX11Info::isPlatformX11()) {
+ return QList<LayoutUnit>();
+ }
+ XkbConfig xkbConfig;
+ QList<LayoutUnit> layouts;
+ if( X11Helper::getGroupNames(QX11Info::display(), &xkbConfig, X11Helper::LAYOUTS_ONLY) ) {
+ for(int i=0; i<xkbConfig.layouts.size(); i++) {
+ QString layout(xkbConfig.layouts[i]);
+ QString variant;
+ if( i<xkbConfig.variants.size() && ! xkbConfig.variants[i].isEmpty() ) {
+ variant = xkbConfig.variants[i];
+ }
+ layouts << LayoutUnit(layout, variant);
+ }
+ // if there are layouts with same map name add numbers to display name
// for(int i=0; i<layouts.length(); i++) {
// int n=1;
// for(int j=i+1; j<layouts.length(); j++) {
// if( layouts[i].layout == layouts[j].layout && layouts[i].getRawDisplayName().isEmpty() ) {
// layouts[i].setDisplayName( addNum(layouts[i].layout, 1) );
// layouts[j].setDisplayName( addNum(layouts[j].layout, ++n) );
-// qDebug() << "Adding" << 1 << "to" << layouts[i].toString();
-// qDebug() << "Adding" << n << "to" << layouts[j].toString();
+// qCDebug(KCM_KEYBOARD) << "Adding" << 1 << "to" << layouts[i].toString();
+// qCDebug(KCM_KEYBOARD) << "Adding" << n << "to" << layouts[j].toString();
// }
// }
// }
- }
- else {
- qWarning() << "Failed to get layout groups from X server";
- }
- return layouts;
+ }
+ else {
+ qWarning() << "Failed to get layout groups from X server";
+ }
+ return layouts;
}
bool X11Helper::setGroup(unsigned int group)
{
- return XkbLockGroup(QX11Info::display(), XkbUseCoreKbd, group);
+ qDebug() << group;
+ xcb_void_cookie_t cookie;
+ cookie = xcb_xkb_latch_lock_state(QX11Info::connection(),
+ XCB_XKB_ID_USE_CORE_KBD,
+ 0, 0,
+ 1,
+ group,
+ 0, 0, 0
+ );
+ xcb_generic_error_t *error = 0;
+ error = xcb_request_check(QX11Info::connection(), cookie);
+ if (error) {
+ qDebug() << "Couldn't change the group" << error->error_code;
+ return false;
+ }
+
+ return true;
}
unsigned int X11Helper::getGroup()
{
- XkbStateRec xkbState;
- XkbGetState( QX11Info::display(), XkbUseCoreKbd, &xkbState );
- return xkbState.group;
+ XkbStateRec xkbState;
+ XkbGetState( QX11Info::display(), XkbUseCoreKbd, &xkbState );
+ return xkbState.group;
}
bool X11Helper::getGroupNames(Display* display, XkbConfig* xkbConfig, FetchType fetchType)
{
- static const char* OPTIONS_SEPARATOR = ",";
-
- Atom real_prop_type;
- int fmt;
- unsigned long nitems, extra_bytes;
- char *prop_data = NULL;
- Status ret;
-
- Atom rules_atom = XInternAtom(display, _XKB_RF_NAMES_PROP_ATOM, False);
-
- /* no such atom! */
- if (rules_atom == None) { /* property cannot exist */
- qWarning() << "Failed to fetch layouts from server:" << "could not find the atom" << _XKB_RF_NAMES_PROP_ATOM;
- return false;
- }
-
- ret = XGetWindowProperty(display,
- DefaultRootWindow(display),
- rules_atom, 0L, _XKB_RF_NAMES_PROP_MAXLEN,
- False, XA_STRING, &real_prop_type, &fmt,
- &nitems, &extra_bytes,
- (unsigned char **) (void *) &prop_data);
-
- /* property not found! */
- if (ret != Success) {
- qWarning() << "Failed to fetch layouts from server:" << "Could not get the property";
- return false;
- }
-
- /* has to be array of strings */
- if ((extra_bytes > 0) || (real_prop_type != XA_STRING) || (fmt != 8)) {
- if (prop_data)
- XFree(prop_data);
- qWarning() << "Failed to fetch layouts from server:" << "Wrong property format";
- return false;
- }
-
-// qDebug() << "prop_data:" << nitems << prop_data;
- QStringList names;
- for(char* p=prop_data; p-prop_data < (long)nitems && p != NULL; p += strlen(p)+1) {
- names.append( p );
-// qDebug() << " " << p;
- }
-
- if( names.count() < 4 ) { //{ rules, model, layouts, variants, options }
- XFree(prop_data);
- return false;
- }
-
- if( fetchType == ALL || fetchType == LAYOUTS_ONLY ) {
- QStringList layouts = names[2].split(OPTIONS_SEPARATOR);
- QStringList variants = names[3].split(OPTIONS_SEPARATOR);
-
- for(int ii=0; ii<layouts.count(); ii++) {
- xkbConfig->layouts << (layouts[ii] != NULL ? layouts[ii] : "");
- xkbConfig->variants << (ii < variants.count() && variants[ii] != NULL ? variants[ii] : "");
- }
-// qDebug() << "Fetched layout groups from X server:"
-// << "\tlayouts:" << xkbConfig->layouts
-// << "\tvariants:" << xkbConfig->variants;
- }
-
- if( fetchType == ALL || fetchType == MODEL_ONLY ) {
- xkbConfig->keyboardModel = (names[1] != NULL ? names[1] : "");
-// qDebug() << "Fetched keyboard model from X server:" << xkbConfig->keyboardModel;
- }
-
- if( fetchType == ALL ) {
- if( names.count() >= 5 ) {
- QString options = (names[4] != NULL ? names[4] : "");
- xkbConfig->options = options.split(OPTIONS_SEPARATOR);
-// qDebug() << "Fetched xkbOptions from X server:" << options;
- }
- }
-
- XFree(prop_data);
- return true;
+ static const char OPTIONS_SEPARATOR[] = ",";
+
+ Atom real_prop_type;
+ int fmt;
+ unsigned long nitems, extra_bytes;
+ char *prop_data = NULL;
+ Status ret;
+
+ Atom rules_atom = XInternAtom(display, _XKB_RF_NAMES_PROP_ATOM, False);
+
+ /* no such atom! */
+ if (rules_atom == None) { /* property cannot exist */
+ qWarning() << "Failed to fetch layouts from server:" << "could not find the atom" << _XKB_RF_NAMES_PROP_ATOM;
+ return false;
+ }
+
+ ret = XGetWindowProperty(display,
+ DefaultRootWindow(display),
+ rules_atom, 0L, _XKB_RF_NAMES_PROP_MAXLEN,
+ False, XA_STRING, &real_prop_type, &fmt,
+ &nitems, &extra_bytes,
+ (unsigned char **) (void *) &prop_data);
+
+ /* property not found! */
+ if (ret != Success) {
+ qWarning() << "Failed to fetch layouts from server:" << "Could not get the property";
+ return false;
+ }
+
+ /* has to be array of strings */
+ if ((extra_bytes > 0) || (real_prop_type != XA_STRING) || (fmt != 8)) {
+ if (prop_data)
+ XFree(prop_data);
+ qWarning() << "Failed to fetch layouts from server:" << "Wrong property format";
+ return false;
+ }
+
+// qCDebug(KCM_KEYBOARD) << "prop_data:" << nitems << prop_data;
+ QStringList names;
+ for(char* p=prop_data; p-prop_data < (long)nitems && p != NULL; p += strlen(p)+1) {
+ names.append( p );
+// kDebug() << " " << p;
+ }
+
+ if( names.count() < 4 ) { //{ rules, model, layouts, variants, options }
+ XFree(prop_data);
+ return false;
+ }
+
+ if( fetchType == ALL || fetchType == LAYOUTS_ONLY ) {
+ QStringList layouts = names[2].split(OPTIONS_SEPARATOR);
+ QStringList variants = names[3].split(OPTIONS_SEPARATOR);
+
+ for(int ii=0; ii<layouts.count(); ii++) {
+ xkbConfig->layouts << (layouts[ii] != NULL ? layouts[ii] : QLatin1String(""));
+ xkbConfig->variants << (ii < variants.count() && variants[ii] != NULL ? variants[ii] : QLatin1String(""));
+ }
+ qDebug() << "Fetched layout groups from X server:"
+ << "\tlayouts:" << xkbConfig->layouts
+ << "\tvariants:" << xkbConfig->variants;
+ }
+
+ if( fetchType == ALL || fetchType == MODEL_ONLY ) {
+ xkbConfig->keyboardModel = (names[1] != NULL ? names[1] : QLatin1String(""));
+ qDebug() << "Fetched keyboard model from X server:" << xkbConfig->keyboardModel;
+ }
+
+ if( fetchType == ALL ) {
+ if( names.count() >= 5 ) {
+ QString options = (names[4] != NULL ? names[4] : QLatin1String(""));
+ xkbConfig->options = options.split(OPTIONS_SEPARATOR);
+ qDebug() << "Fetched xkbOptions from X server:" << options;
+ }
+ }
+
+ XFree(prop_data);
+ return true;
}
-XEventNotifier::XEventNotifier(QWidget* parent):
- QWidget(parent),
- xkbOpcode(-1)
+XEventNotifier::XEventNotifier():
+ xkbOpcode(-1)
{
- // KF5 TODO: Figure out the proper way to check for this
-// if( KApplication::kApplication() == NULL ) {
-// qWarning() << "Layout Widget won't work properly without KApplication instance";
-// }
+ if( QCoreApplication::instance() == NULL ) {
+ qWarning() << "Layout Widget won't work properly without QCoreApplication instance";
+ }
}
void XEventNotifier::start()
{
- // KF5 TODO: Figure out the proper way to check for this
-// if( KApplication::kApplication() != NULL && X11Helper::xkbSupported(&xkbOpcode) ) {
-// registerForXkbEvents(QX11Info::display());
-//
-// // start the event loop
-// KApplication::kApplication()->installX11EventFilter(this);
-// }
+ qDebug() << "qCoreApp" << QCoreApplication::instance();
+ if( QCoreApplication::instance() != NULL && X11Helper::xkbSupported(&xkbOpcode) ) {
+ registerForXkbEvents(QX11Info::display());
+
+ // start the event loop
+ QCoreApplication::instance()->installNativeEventFilter(this);
+ }
}
void XEventNotifier::stop()
{
- // KF5 TODO: Figure out the proper way to check for this
-// if( KApplication::kApplication() != NULL ) {
-// //TODO: unregister
-// // XEventNotifier::unregisterForXkbEvents(QX11Info::display());
-//
-// // stop the event loop
-// KApplication::kApplication()->removeX11EventFilter(this);
-// }
+ if( QCoreApplication::instance() != NULL ) {
+ //TODO: unregister
+ // XEventNotifier::unregisterForXkbEvents(QX11Info::display());
+
+ // stop the event loop
+ QCoreApplication::instance()->removeNativeEventFilter(this);
+ }
}
-bool XEventNotifier::isXkbEvent(XEvent* event)
+
+bool XEventNotifier::isXkbEvent(xcb_generic_event_t* event)
{
- return event->type == xkbOpcode;
+// kDebug() << "event response type:" << (event->response_type & ~0x80) << xkbOpcode << ((event->response_type & ~0x80) == xkbOpcode + XkbEventCode);
+ return (event->response_type & ~0x80) == xkbOpcode + XkbEventCode;
}
-bool XEventNotifier::processOtherEvents(XEvent* /*event*/)
+bool XEventNotifier::processOtherEvents(xcb_generic_event_t* /*event*/)
{
- return true;
+ return true;
}
-bool XEventNotifier::processXkbEvents(XEvent* event)
+bool XEventNotifier::processXkbEvents(xcb_generic_event_t* event)
{
- if( XEventNotifier::isGroupSwitchEvent(event) ) {
- emit(layoutChanged());
- }
- else if( XEventNotifier::isLayoutSwitchEvent(event) ) {
- emit(layoutMapChanged());
- }
- return true;
+ _xkb_event *xkbevt = reinterpret_cast<_xkb_event *>(event);
+ if( XEventNotifier::isGroupSwitchEvent(xkbevt) ) {
+// kDebug() << "group switch event";
+ emit(layoutChanged());
+ }
+ else if( XEventNotifier::isLayoutSwitchEvent(xkbevt) ) {
+// kDebug() << "layout switch event";
+ emit(layoutMapChanged());
+ }
+ return true;
}
-bool XEventNotifier::x11Event(XEvent * event)
+bool XEventNotifier::nativeEventFilter(const QByteArray &eventType, void *message, long *)
{
- // qApp->x11ProcessEvent ( event );
- if( isXkbEvent(event) ) {
- processXkbEvents(event);
- }
- else {
- processOtherEvents(event);
- }
- // KF5 TODO: Figure out the equivalent
-// return QWidget::x11Event(event);
- return true;
+// kDebug() << "event type:" << eventType;
+ if (eventType == "xcb_generic_event_t") {
+ xcb_generic_event_t* ev = static_cast<xcb_generic_event_t *>(message);
+ if( isXkbEvent(ev) ) {
+ processXkbEvents(ev);
+ }
+ else {
+ processOtherEvents(ev);
+ }
+ }
+ return false;
}
-bool XEventNotifier::isGroupSwitchEvent(XEvent* event)
+//bool XEventNotifier::x11Event(XEvent * event)
+//{
+// // qApp->x11ProcessEvent ( event );
+// if( isXkbEvent(event) ) {
+// processXkbEvents(event);
+// }
+// else {
+// processOtherEvents(event);
+// }
+// return QWidget::x11Event(event);
+//}
+
+bool XEventNotifier::isGroupSwitchEvent(_xkb_event* xkbEvent)
{
- XkbEvent *xkbEvent = (XkbEvent*) event;
+// XkbEvent *xkbEvent = (XkbEvent*) event;
#define GROUP_CHANGE_MASK \
( XkbGroupStateMask | XkbGroupBaseMask | XkbGroupLatchMask | XkbGroupLockMask )
- return xkbEvent->any.xkb_type == XkbStateNotify && xkbEvent->state.changed & GROUP_CHANGE_MASK;
+ return xkbEvent->any.xkbType == XkbStateNotify && (xkbEvent->state_notify.changed & GROUP_CHANGE_MASK);
}
-bool XEventNotifier::isLayoutSwitchEvent(XEvent* event)
+bool XEventNotifier::isLayoutSwitchEvent(_xkb_event* xkbEvent)
{
- XkbEvent *xkbEvent = (XkbEvent*) event;
+// XkbEvent *xkbEvent = (XkbEvent*) event;
return //( (xkbEvent->any.xkb_type == XkbMapNotify) && (xkbEvent->map.changed & XkbKeySymsMask) ) ||
/* || ( (xkbEvent->any.xkb_type == XkbNamesNotify) && (xkbEvent->names.changed & XkbGroupNamesMask) || )*/
- (xkbEvent->any.xkb_type == XkbNewKeyboardNotify);
+ (xkbEvent->any.xkbType == XkbNewKeyboardNotify);
}
int XEventNotifier::registerForXkbEvents(Display* display)
{
int eventMask = XkbNewKeyboardNotifyMask | XkbStateNotifyMask;
if( ! XkbSelectEvents(display, XkbUseCoreKbd, eventMask, eventMask) ) {
- qWarning() << "Couldn't select desired XKB events";
- return false;
+ qWarning() << "Couldn't select desired XKB events";
+ return false;
}
return true;
}
-static const char* LAYOUT_VARIANT_SEPARATOR_PREFIX = "(";
-static const char* LAYOUT_VARIANT_SEPARATOR_SUFFIX = ")";
+static const char LAYOUT_VARIANT_SEPARATOR_PREFIX[] = "(";
+static const char LAYOUT_VARIANT_SEPARATOR_SUFFIX[] = ")";
static QString& stripVariantName(QString& variant)
{
- if( variant.endsWith(LAYOUT_VARIANT_SEPARATOR_SUFFIX) ) {
- int suffixLen = strlen(LAYOUT_VARIANT_SEPARATOR_SUFFIX);
- return variant.remove(variant.length()-suffixLen, suffixLen);
- }
- return variant;
+ if( variant.endsWith(LAYOUT_VARIANT_SEPARATOR_SUFFIX) ) {
+ int suffixLen = strlen(LAYOUT_VARIANT_SEPARATOR_SUFFIX);
+ return variant.remove(variant.length()-suffixLen, suffixLen);
+ }
+ return variant;
}
LayoutUnit::LayoutUnit(const QString& fullLayoutName)
{
- QStringList lv = fullLayoutName.split(LAYOUT_VARIANT_SEPARATOR_PREFIX);
- layout = lv[0];
- variant = lv.size() > 1 ? stripVariantName(lv[1]) : "";
+ QStringList lv = fullLayoutName.split(LAYOUT_VARIANT_SEPARATOR_PREFIX);
+ layout = lv[0];
+ variant = lv.size() > 1 ? stripVariantName(lv[1]) : QLatin1String("");
}
QString LayoutUnit::toString() const
{
- if( variant.isEmpty() )
- return layout;
+ if( variant.isEmpty() )
+ return layout;
- return layout + LAYOUT_VARIANT_SEPARATOR_PREFIX+variant+LAYOUT_VARIANT_SEPARATOR_SUFFIX;
+ return layout + LAYOUT_VARIANT_SEPARATOR_PREFIX+variant+LAYOUT_VARIANT_SEPARATOR_SUFFIX;
}
const int LayoutUnit::MAX_LABEL_LENGTH = 3;
diff --git a/src/x11_helper.h b/src/x11_helper.h
index 60fa65f..a2408dd 100644
--- a/src/x11_helper.h
+++ b/src/x11_helper.h
@@ -20,164 +20,236 @@
#ifndef X11_HELPER_H_
#define X11_HELPER_H_
-#include <QDebug>
#include <QKeySequence>
#include <QString>
#include <QStringList>
#include <QWidget>
+#include <QX11Info>
+#include <QAbstractNativeEventFilter>
-#include <X11/Xlib.h>
+#include <xcb/xcb.h>
-
-class XEventNotifier : public QWidget {
- Q_OBJECT
+namespace
+{
+typedef struct _xcb_xkb_map_notify_event_t {
+ uint8_t response_type;
+ uint8_t xkbType;
+ uint16_t sequence;
+ xcb_timestamp_t time;
+ uint8_t deviceID;
+ uint8_t ptrBtnActions;
+ uint16_t changed;
+ xcb_keycode_t minKeyCode;
+ xcb_keycode_t maxKeyCode;
+ uint8_t firstType;
+ uint8_t nTypes;
+ xcb_keycode_t firstKeySym;
+ uint8_t nKeySyms;
+ xcb_keycode_t firstKeyAct;
+ uint8_t nKeyActs;
+ xcb_keycode_t firstKeyBehavior;
+ uint8_t nKeyBehavior;
+ xcb_keycode_t firstKeyExplicit;
+ uint8_t nKeyExplicit;
+ xcb_keycode_t firstModMapKey;
+ uint8_t nModMapKeys;
+ xcb_keycode_t firstVModMapKey;
+ uint8_t nVModMapKeys;
+ uint16_t virtualMods;
+ uint8_t pad0[2];
+} _xcb_xkb_map_notify_event_t;
+typedef struct _xcb_xkb_state_notify_event_t {
+ uint8_t response_type;
+ uint8_t xkbType;
+ uint16_t sequence;
+ xcb_timestamp_t time;
+ uint8_t deviceID;
+ uint8_t mods;
+ uint8_t baseMods;
+ uint8_t latchedMods;
+ uint8_t lockedMods;
+ uint8_t group;
+ int16_t baseGroup;
+ int16_t latchedGroup;
+ uint8_t lockedGroup;
+ uint8_t compatState;
+ uint8_t grabMods;
+ uint8_t compatGrabMods;
+ uint8_t lookupMods;
+ uint8_t compatLoockupMods;
+ uint16_t ptrBtnState;
+ uint16_t changed;
+ xcb_keycode_t keycode;
+ uint8_t eventType;
+ uint8_t requestMajor;
+ uint8_t requestMinor;
+} _xcb_xkb_state_notify_event_t;
+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;
+}
+
+class XEventNotifier : public QObject, public QAbstractNativeEventFilter {
+ Q_OBJECT
Q_SIGNALS:
- void layoutChanged();
- void layoutMapChanged();
+ void layoutChanged();
+ void layoutMapChanged();
public:
- explicit XEventNotifier(QWidget* parent=NULL);
- virtual ~XEventNotifier() {}
+ XEventNotifier();
+ virtual ~XEventNotifier() {}
- virtual void start();
- virtual void stop();
+ virtual void start();
+ virtual void stop();
protected:
- bool x11Event(XEvent * e);
- virtual bool processOtherEvents(XEvent* e);
- virtual bool processXkbEvents(XEvent* e);
+// bool x11Event(XEvent * e);
+ virtual bool processOtherEvents(xcb_generic_event_t* e);
+ virtual bool processXkbEvents(xcb_generic_event_t* e);
+ virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE;
private:
- int registerForXkbEvents(Display* display);
- bool isXkbEvent(XEvent* event);
- bool isGroupSwitchEvent(XEvent* event);
- bool isLayoutSwitchEvent(XEvent* event);
+ int registerForXkbEvents(Display* display);
+ bool isXkbEvent(xcb_generic_event_t* event);
+ bool isGroupSwitchEvent(_xkb_event* event);
+ bool isLayoutSwitchEvent(_xkb_event* event);
- int xkbOpcode;
+ int xkbOpcode;
};
struct XkbConfig {
- QString keyboardModel;
- QStringList layouts;
- QStringList variants;
- QStringList options;
+ QString keyboardModel;
+ QStringList layouts;
+ QStringList variants;
+ QStringList options;
- bool isValid() { return ! layouts.empty(); }
+ bool isValid() { return ! layouts.empty(); }
};
struct LayoutUnit {
- static const int MAX_LABEL_LENGTH;
-
- //TODO: move these to private?
- QString layout;
- QString variant;
-
- LayoutUnit() {}
- explicit LayoutUnit(const QString& fullLayoutName);
- LayoutUnit(const QString& layout_, const QString& variant_) {
- layout = layout_;
- variant = variant_;
- }
- /*explicit*/ LayoutUnit(const LayoutUnit& layoutUnit) {
- layout = layoutUnit.layout;
- variant = layoutUnit.variant;
- displayName = layoutUnit.displayName;
- shortcut = layoutUnit.shortcut;
- }
-
- QString getRawDisplayName() const { return displayName; }
- QString getDisplayName() const { return !displayName.isEmpty() ? displayName : layout; }
- void setDisplayName(const QString& name) { displayName = name; }
-
- void setShortcut(const QKeySequence& shortcut) { this->shortcut = shortcut; }
- QKeySequence getShortcut() const { return shortcut; }
-
- bool isEmpty() const { return layout.isEmpty(); }
- bool isValid() const { return ! isEmpty(); }
- bool operator==(const LayoutUnit& layoutItem) const {
- return layout==layoutItem.layout && variant==layoutItem.variant;
- }
- bool operator!=(const LayoutUnit& layoutItem) const {
- return ! (*this == layoutItem);
- }
- QString toString() const;
+ static const int MAX_LABEL_LENGTH;
+
+ //TODO: move these to private?
+ QString layout;
+ QString variant;
+
+ LayoutUnit() {}
+ explicit LayoutUnit(const QString& fullLayoutName);
+ LayoutUnit(const QString& layout_, const QString& variant_) {
+ layout = layout_;
+ variant = variant_;
+ }
+ /*explicit*/ LayoutUnit(const LayoutUnit& layoutUnit) {
+ layout = layoutUnit.layout;
+ variant = layoutUnit.variant;
+ displayName = layoutUnit.displayName;
+ shortcut = layoutUnit.shortcut;
+ }
+
+ QString getRawDisplayName() const { return displayName; }
+ QString getDisplayName() const { return !displayName.isEmpty() ? displayName : layout; }
+ void setDisplayName(const QString& name) { displayName = name; }
+
+ void setShortcut(const QKeySequence& shortcut) { this->shortcut = shortcut; }
+ QKeySequence getShortcut() const { return shortcut; }
+
+ bool isEmpty() const { return layout.isEmpty(); }
+ bool isValid() const { return ! isEmpty(); }
+ bool operator==(const LayoutUnit& layoutItem) const {
+ return layout==layoutItem.layout && variant==layoutItem.variant;
+ }
+ bool operator!=(const LayoutUnit& layoutItem) const {
+ return ! (*this == layoutItem);
+ }
+ QString toString() const;
private:
- QString displayName;
- QKeySequence shortcut;
+ QString displayName;
+ QKeySequence shortcut;
};
struct LayoutSet {
- QList<LayoutUnit> layouts;
- LayoutUnit currentLayout;
-
- LayoutSet() {}
-
- LayoutSet(const LayoutSet& currentLayouts) {
- this->layouts = currentLayouts.layouts;
- this->currentLayout = currentLayouts.currentLayout;
- }
-
- bool isValid() const {
- return currentLayout.isValid() && layouts.contains(currentLayout);
- }
-
- bool operator == (const LayoutSet& currentLayouts) const {
- return this->layouts == currentLayouts.layouts
- && this->currentLayout == currentLayouts.currentLayout;
- }
-
- LayoutSet& operator = (const LayoutSet& currentLayouts) {
- this->layouts = currentLayouts.layouts;
- this->currentLayout = currentLayouts.currentLayout;
- return *this;
- }
-
- QString toString() const {
- QString str(currentLayout.toString());
- str += ": ";
- foreach(const LayoutUnit& layoutUnit, layouts) {
- str += layoutUnit.toString() + " ";
- }
- return str;
- }
-
- static QString toString(const QList<LayoutUnit>& layoutUnits) {
- QString str;
- foreach(const LayoutUnit& layoutUnit, layoutUnits) {
- str += layoutUnit.toString() + ",";
- }
- return str;
- }
+ QList<LayoutUnit> layouts;
+ LayoutUnit currentLayout;
+
+ LayoutSet() {}
+
+ LayoutSet(const LayoutSet& currentLayouts) {
+ this->layouts = currentLayouts.layouts;
+ this->currentLayout = currentLayouts.currentLayout;
+ }
+
+ bool isValid() const {
+ return currentLayout.isValid() && layouts.contains(currentLayout);
+ }
+
+ bool operator == (const LayoutSet& currentLayouts) const {
+ return this->layouts == currentLayouts.layouts
+ && this->currentLayout == currentLayouts.currentLayout;
+ }
+
+ LayoutSet& operator = (const LayoutSet& currentLayouts) {
+ this->layouts = currentLayouts.layouts;
+ this->currentLayout = currentLayouts.currentLayout;
+ return *this;
+ }
+
+ QString toString() const {
+ QString str(currentLayout.toString());
+ str += QLatin1String(": ");
+ foreach(const LayoutUnit& layoutUnit, layouts) {
+ str += layoutUnit.toString() + " ";
+ }
+ return str;
+ }
+
+ static QString toString(const QList<LayoutUnit>& layoutUnits) {
+ QString str;
+ foreach(const LayoutUnit& layoutUnit, layoutUnits) {
+ str += layoutUnit.toString() + ",";
+ }
+ return str;
+ }
};
class X11Helper
{
public:
- static int MAX_GROUP_COUNT;
- static const char* LEFT_VARIANT_STR;
- static const char* RIGHT_VARIANT_STR;
+ static const int MAX_GROUP_COUNT;
+ static const int ARTIFICIAL_GROUP_LIMIT_COUNT;
+
+ static const char LEFT_VARIANT_STR[];
+ static const char RIGHT_VARIANT_STR[];
- static bool xkbSupported(int* xkbOpcode);
+ static bool xkbSupported(int* xkbOpcode);
- static void switchToNextLayout();
- static void scrollLayouts(int delta);
- static bool isDefaultLayout();
- static bool setDefaultLayout();
- static bool setLayout(const LayoutUnit& layout);
- static LayoutUnit getCurrentLayout();
- static LayoutSet getCurrentLayouts();
- static QList<LayoutUnit> getLayoutsList();
- static QStringList getLayoutsListAsString(const QList<LayoutUnit>& layoutsList);
+ static void switchToNextLayout();
+ static void scrollLayouts(int delta);
+ static bool isDefaultLayout();
+ static bool setDefaultLayout();
+ static bool setLayout(const LayoutUnit& layout);
+ static LayoutUnit getCurrentLayout();
+ static LayoutSet getCurrentLayouts();
+ static QList<LayoutUnit> getLayoutsList();
+ static QStringList getLayoutsListAsString(const QList<LayoutUnit>& layoutsList);
- enum FetchType { ALL, LAYOUTS_ONLY, MODEL_ONLY };
- static bool getGroupNames(Display* dpy, XkbConfig* xkbConfig, FetchType fetchType);
+ enum FetchType { ALL, LAYOUTS_ONLY, MODEL_ONLY };
+ static bool getGroupNames(Display* dpy, XkbConfig* xkbConfig, FetchType fetchType);
private:
- static unsigned int getGroup();
- static bool setGroup(unsigned int group);
+ static unsigned int getGroup();
+ static bool setGroup(unsigned int group);
};
#endif /* X11_HELPER_H_ */