diff options
author | Bradley T. Hughes <bradley.hughes@nokia.com> | 2010-03-10 10:13:33 (GMT) |
---|---|---|
committer | Bradley T. Hughes <bradley.hughes@nokia.com> | 2010-03-15 15:02:58 (GMT) |
commit | 761bccd408c72e1d1d10d6c69f9f1d01fff30a0c (patch) | |
tree | b94e1d15e9e3b5637675dbd8b59bdd72af09c011 /src/gui | |
parent | c63fe6fcfc83028419dd84d13d24e7cb1295ac7f (diff) | |
download | Qt-761bccd408c72e1d1d10d6c69f9f1d01fff30a0c.zip Qt-761bccd408c72e1d1d10d6c69f9f1d01fff30a0c.tar.gz Qt-761bccd408c72e1d1d10d6c69f9f1d01fff30a0c.tar.bz2 |
Improve keyboard layout detection on X11
When the keyboard configuration includes multiple layouts in separate
groups, the _XKB_RULES_NAME property lists the layouts separated by a
comma. Previously we did not handle this.
We query the current keyboard group on startup and monitor
XkbStateNotify events for group changes. The existing infrastructre
from QKeyMapper deals with sending the KeyboardLayoutChange event to
all toplevel windows already.
This change includes a bit of refactoring to put the XKB detection and
initialization in qapplication_x11.cpp and XKB opcode, eventbase, and
errorbase into qt_x11_p.h (like with the other extensions).
Task-number: QTBUG-3631
Reviewed-by: denis
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/kernel/qapplication_x11.cpp | 63 | ||||
-rw-r--r-- | src/gui/kernel/qkeymapper_p.h | 2 | ||||
-rw-r--r-- | src/gui/kernel/qkeymapper_x11.cpp | 34 | ||||
-rw-r--r-- | src/gui/kernel/qt_x11_p.h | 6 |
4 files changed, 78 insertions, 27 deletions
diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 20a7ff2..985f825 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -709,6 +709,10 @@ static int qt_x_errhandler(Display *dpy, XErrorEvent *err) extensionName = "XInputExtension"; else if (err->request_code == X11->mitshm_major) extensionName = "MIT-SHM"; +#ifndef QT_NO_XKB + else if(err->request_code == X11->xkb_major) + extensionName = "XKEYBOARD"; +#endif char minor_str[256]; if (extensionName) { @@ -1635,6 +1639,11 @@ void qt_init(QApplicationPrivate *priv, int, X11->xinput_eventbase = 0; X11->xinput_errorbase = 0; + X11->use_xkb = false; + X11->xkb_major = 0; + X11->xkb_eventbase = 0; + X11->xkb_errorbase = 0; + // MIT-SHM X11->use_mitshm = false; X11->use_mitshm_pixmaps = false; @@ -2108,6 +2117,33 @@ void qt_init(QApplicationPrivate *priv, int, } #endif // QT_NO_XINPUT +#ifndef QT_NO_XKB + int xkblibMajor = XkbMajorVersion; + int xkblibMinor = XkbMinorVersion; + X11->use_xkb = XkbQueryExtension(X11->display, + &X11->xkb_major, + &X11->xkb_eventbase, + &X11->xkb_errorbase, + &xkblibMajor, + &xkblibMinor); + if (X11->use_xkb) { + // If XKB is detected, set the GrabsUseXKBState option so input method + // compositions continue to work (ie. deadkeys) + unsigned int state = XkbPCF_GrabsUseXKBStateMask; + (void) XkbSetPerClientControls(X11->display, state, &state); + + // select for group change events + XkbSelectEventDetails(X11->display, + XkbUseCoreKbd, + XkbStateNotify, + XkbAllStateComponentsMask, + XkbGroupStateMask); + + // current group state is queried when creating the keymapper, no need to do it here + } +#endif + + #if !defined(QT_NO_FONTCONFIG) int dpi = 0; getXDefault("Xft", FC_DPI, &dpi); @@ -2186,15 +2222,6 @@ void qt_init(QApplicationPrivate *priv, int, // initialize key mapper QKeyMapper::changeKeyboard(); -#ifndef QT_NO_XKB - if (qt_keymapper_private()->useXKB) { - // If XKB is detected, set the GrabsUseXKBState option so input method - // compositions continue to work (ie. deadkeys) - unsigned int state = XkbPCF_GrabsUseXKBStateMask; - (void) XkbSetPerClientControls(X11->display, state, &state); - } -#endif // QT_NO_XKB - // Misc. initialization #if 0 //disabled for now.. QSegfaultHandler::initialize(priv->argv, priv->argc); @@ -3229,6 +3256,24 @@ int QApplication::x11ProcessEvent(XEvent* event) QKeyMapper::changeKeyboard(); return 0; } +#ifndef QT_NO_XKB + else if (X11->use_xkb && event->type == X11->xkb_eventbase) { + XkbAnyEvent *xkbevent = (XkbAnyEvent *) event; + switch (xkbevent->xkb_type) { + case XkbStateNotify: + { + XkbStateNotifyEvent *xkbstateevent = (XkbStateNotifyEvent *) xkbevent; + if ((xkbstateevent->changed & XkbGroupStateMask) != 0) { + qt_keymapper_private()->xkb_currentGroup = xkbstateevent->group; + QKeyMapper::changeKeyboard(); + } + break; + } + default: + break; + } + } +#endif if (!widget) { // don't know this windows QWidget* popup = QApplication::activePopupWidget(); diff --git a/src/gui/kernel/qkeymapper_p.h b/src/gui/kernel/qkeymapper_p.h index 3e42d6e..38f141e 100644 --- a/src/gui/kernel/qkeymapper_p.h +++ b/src/gui/kernel/qkeymapper_p.h @@ -183,7 +183,7 @@ public: const XEvent *, bool grab); - bool useXKB; + int xkb_currentGroup; QXCoreDesc coreDesc; #elif defined(Q_WS_MAC) diff --git a/src/gui/kernel/qkeymapper_x11.cpp b/src/gui/kernel/qkeymapper_x11.cpp index d6d1042..428ac3e 100644 --- a/src/gui/kernel/qkeymapper_x11.cpp +++ b/src/gui/kernel/qkeymapper_x11.cpp @@ -248,22 +248,17 @@ qt_XTranslateKey(register QXCoreDesc *dpy, QKeyMapperPrivate::QKeyMapperPrivate() - : keyboardInputDirection(Qt::LeftToRight), useXKB(false) + : keyboardInputDirection(Qt::LeftToRight), xkb_currentGroup(0) { memset(&coreDesc, 0, sizeof(coreDesc)); #ifndef QT_NO_XKB - int opcode = -1; - int xkbEventBase = -1; - int xkbErrorBase = -1; - int xkblibMajor = XkbMajorVersion; - int xkblibMinor = XkbMinorVersion; - if (XkbQueryExtension(X11->display, &opcode, &xkbEventBase, &xkbErrorBase, &xkblibMajor, &xkblibMinor)) - useXKB = true; -#endif - -#if 0 - qDebug() << "useXKB =" << useXKB; + if (X11->use_xkb) { + // get the current group + XkbStateRec xkbState; + if (XkbGetState(X11->display, XkbUseCoreKbd, &xkbState) == Success) + xkb_currentGroup = xkbState.group; + } #endif } @@ -276,7 +271,7 @@ QKeyMapperPrivate::~QKeyMapperPrivate() QList<int> QKeyMapperPrivate::possibleKeys(QKeyEvent *event) { #ifndef QT_NO_XKB - if (useXKB) + if (X11->use_xkb) return possibleKeysXKB(event); #endif return possibleKeysCore(event); @@ -486,7 +481,7 @@ enum { void QKeyMapperPrivate::clearMappings() { #ifndef QT_NO_XKB - if (useXKB) { + if (X11->use_xkb) { // try to determine the layout name and input direction by reading the _XKB_RULES_NAMES property off // the root window QByteArray layoutName; @@ -515,8 +510,13 @@ void QKeyMapperPrivate::clearMappings() p += qstrlen(p) + 1; } while (p < end); - layoutName = QByteArray::fromRawData(names[2], qstrlen(names[2])); - variantName = QByteArray::fromRawData(names[3], qstrlen(names[3])); + // the layout names and variants are saved in the _XKB_RULES_NAMES property as a comma separated list + QList<QByteArray> layoutNames = QByteArray::fromRawData(names[2], qstrlen(names[2])).split(','); + if (uint(xkb_currentGroup) < uint(layoutNames.count())) + layoutName = layoutNames.at(xkb_currentGroup); + QList<QByteArray> variantNames = QByteArray::fromRawData(names[3], qstrlen(names[3])).split(','); + if (uint(xkb_currentGroup) < uint(variantNames.count())) + variantName = variantNames.at(xkb_currentGroup); } // ### ??? @@ -574,7 +574,7 @@ void QKeyMapperPrivate::clearMappings() // look at the modifier mapping, and get the correct masks for alt, meta, super, hyper, and mode_switch #ifndef QT_NO_XKB - if (useXKB) { + if (X11->use_xkb) { XkbDescPtr xkbDesc = XkbGetMap(X11->display, XkbAllClientInfoMask, XkbUseCoreKbd); for (int i = xkbDesc->min_key_code; i < xkbDesc->max_key_code; ++i) { const uint mask = xkbDesc->map->modmap ? xkbDesc->map->modmap[i] : 0; diff --git a/src/gui/kernel/qt_x11_p.h b/src/gui/kernel/qt_x11_p.h index 8af4df5..e1b2625 100644 --- a/src/gui/kernel/qt_x11_p.h +++ b/src/gui/kernel/qt_x11_p.h @@ -439,6 +439,12 @@ struct QX11Data int xinput_eventbase; int xinput_errorbase; + // for XKEYBOARD support + bool use_xkb; + int xkb_major; + int xkb_eventbase; + int xkb_errorbase; + QList<QWidget *> deferred_map; struct ScrollInProgress { long id; |