diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | generic/tkInt.h | 1 | ||||
-rw-r--r-- | unix/tkUnixEvent.c | 33 | ||||
-rw-r--r-- | unix/tkUnixKey.c | 48 |
4 files changed, 65 insertions, 21 deletions
@@ -2,6 +2,10 @@ * tests/window.test: Bring back test window-2.9. No longer hangs. + * generic/tkInt.h: [Bug 3607830] Runtime checks that Xkb is + * unix/tkUnixEvent.c: available in the X server before trying to + * unix/tkUnixKey.c: use. Adapted from patch from Brian Griffin. + 2013-03-27 Jan Nijtmans <nijtmans@users.sf.net> * library/button.tcl: [Bug 3608074]: Add <<Invoke>> bindings to diff --git a/generic/tkInt.h b/generic/tkInt.h index 21b882c..933fa5e 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -526,6 +526,7 @@ typedef struct TkDisplay { #define TK_DISPLAY_USE_IM (1 << 1) #define TK_DISPLAY_WM_TRACING (1 << 3) #define TK_DISPLAY_IN_WARP (1 << 4) +#define TK_DISPLAY_USE_XKB (1 << 5) /* * One of the following structures exists for each error handler created by a diff --git a/unix/tkUnixEvent.c b/unix/tkUnixEvent.c index c540157..473a7b8 100644 --- a/unix/tkUnixEvent.c +++ b/unix/tkUnixEvent.c @@ -12,6 +12,14 @@ #include "tkUnixInt.h" #include <signal.h> +#ifdef HAVE_XKBKEYCODETOKEYSYM +# include <X11/XKBlib.h> +/* Work around stupid un-const-ified Xkb headers. Grrrrr.... */ +# define XkbOpenDisplay(D,V,E,M,m,R) \ + (XkbOpenDisplay)((char *)(D),(V),(E),(M),(m),(R)) +#else +# define XkbOpenDisplay(D,V,E,M,m,R) (NULL) +#endif /* * The following static indicates whether this module has been initialized in @@ -117,6 +125,12 @@ TkpOpenDisplay( { TkDisplay *dispPtr; Display *display; + int event = 0; + int error = 0; + int major = 1; + int minor = 0; + int reason = 0; + unsigned int use_xkb = 0; #ifdef TCL_THREADS static int xinited = 0; TCL_DECLARE_MUTEX(xinitMutex); @@ -134,13 +148,30 @@ TkpOpenDisplay( } #endif - display = XOpenDisplay(displayNameStr); + /* + ** Bug [3607830]: Before using Xkb, it must be initialized and confirmed + ** that the serve supports it. The XkbOpenDisplay call + ** will perform this check and return NULL if the extension + ** is not supported. + */ + display = XkbOpenDisplay(displayNameStr, &event, &error, &major, &minor, &reason); + + if (display == NULL) { + /*fprintf(stderr,"event=%d error=%d major=%d minor=%d reason=%d\nDisabling xkb\n", + event, error, major, minor, reason);*/ + display = XOpenDisplay(displayNameStr); + } else { + use_xkb = TK_DISPLAY_USE_XKB; + /*fprintf(stderr, "Using xkb %d.%d\n", major, minor);*/ + } + if (display == NULL) { return NULL; } dispPtr = ckalloc(sizeof(TkDisplay)); memset(dispPtr, 0, sizeof(TkDisplay)); dispPtr->display = display; + dispPtr->flags |= use_xkb; #ifdef TK_USE_INPUT_METHODS OpenIM(dispPtr); #endif diff --git a/unix/tkUnixKey.c b/unix/tkUnixKey.c index 5ea90f4..23c4aa4 100644 --- a/unix/tkUnixKey.c +++ b/unix/tkUnixKey.c @@ -12,11 +12,20 @@ #include "tkInt.h" +/* +** Bug [3607830]: Before using Xkb, it must be initialized. TkpOpenDisplay +** does this and sets the USE_XKB flag if xkb is supported. +** (should this be function ptr?) +*/ #ifdef HAVE_XKBKEYCODETOKEYSYM # include <X11/XKBlib.h> #else # define XkbKeycodeToKeysym(D,K,G,L) XKeycodeToKeysym(D,K,L) #endif +#define TkKeycodeToKeysym(D,K,G,L) \ + ((D)->flags & TK_DISPLAY_USE_XKB) ? \ + XkbKeycodeToKeysym((D)->display,K,G,L) : \ + XKeycodeToKeysym((D)->display,K,L) /* * Prototypes for local functions defined in this file: @@ -216,7 +225,7 @@ TkpGetString( /* * When mapping from a keysym to a keycode, need information about the - * modifier state to be used so that when they call XkbKeycodeToKeysym taking + * modifier state to be used so that when they call TkKeycodeToKeysym taking * into account the xkey.state, they will get back the original keysym. */ @@ -226,27 +235,26 @@ TkpSetKeycodeAndState( KeySym keySym, XEvent *eventPtr) { - Display *display = Tk_Display(tkwin); + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; int state; KeyCode keycode; if (keySym == NoSymbol) { keycode = 0; } else { - keycode = XKeysymToKeycode(display, keySym); - if (keycode != 0) { - for (state = 0; state < 4; state++) { - if (XkbKeycodeToKeysym(display, keycode, 0, state) == keySym){ - if (state & 1) { - eventPtr->xkey.state |= ShiftMask; - } - if (state & 2) { - TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - - eventPtr->xkey.state |= dispPtr->modeModMask; - } - break; + keycode = XKeysymToKeycode(dispPtr->display, keySym); + } + eventPtr->xkey.keycode = keycode; + if (keycode != 0) { + for (state = 0; state < 4; state++) { + if (XLookupKeysym(&eventPtr->xkey, state) == keySym) { + if (state & 1) { + eventPtr->xkey.state |= ShiftMask; + } + if (state & 2) { + eventPtr->xkey.state |= dispPtr->modeModMask; } + break; } } } @@ -328,7 +336,7 @@ TkpGetKeySym( && (eventPtr->xkey.state & LockMask))) { index += 1; } - sym = XkbKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, 0, + sym = TkKeycodeToKeysym(dispPtr, eventPtr->xkey.keycode, 0, index); /* @@ -343,7 +351,7 @@ TkpGetKeySym( || ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) || ((sym >= XK_Ooblique) && (sym <= XK_Thorn)))) { index &= ~1; - sym = XkbKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, + sym = TkKeycodeToKeysym(dispPtr, eventPtr->xkey.keycode, 0, index); } } @@ -354,7 +362,7 @@ TkpGetKeySym( */ if ((index & 1) && (sym == NoSymbol)) { - sym = XkbKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, + sym = TkKeycodeToKeysym(dispPtr, eventPtr->xkey.keycode, 0, index & ~1); } return sym; @@ -404,7 +412,7 @@ TkpInitKeymapInfo( if (*codePtr == 0) { continue; } - keysym = XkbKeycodeToKeysym(dispPtr->display, *codePtr, 0, 0); + keysym = TkKeycodeToKeysym(dispPtr, *codePtr, 0, 0); if (keysym == XK_Shift_Lock) { dispPtr->lockUsage = LU_SHIFT; break; @@ -430,7 +438,7 @@ TkpInitKeymapInfo( if (*codePtr == 0) { continue; } - keysym = XkbKeycodeToKeysym(dispPtr->display, *codePtr, 0, 0); + keysym = TkKeycodeToKeysym(dispPtr, *codePtr, 0, 0); if (keysym == XK_Mode_switch) { dispPtr->modeModMask |= ShiftMask << (i/modMapPtr->max_keypermod); } |