diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2010-01-02 11:07:55 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2010-01-02 11:07:55 (GMT) |
commit | 8a3e46aada6943f89dfdb746116c20fe332535eb (patch) | |
tree | 74ec102e33450a1e4e9ce197bebd5e9082d2738f /unix | |
parent | 1a86dacbaaea58d12f5c210efdd06d8974adc362 (diff) | |
download | tk-8a3e46aada6943f89dfdb746116c20fe332535eb.zip tk-8a3e46aada6943f89dfdb746116c20fe332535eb.tar.gz tk-8a3e46aada6943f89dfdb746116c20fe332535eb.tar.bz2 |
Fix [Bug 1373712] and [Bug 1924761].
Diffstat (limited to 'unix')
-rw-r--r-- | unix/tkUnixEvent.c | 35 | ||||
-rw-r--r-- | unix/tkUnixKey.c | 109 |
2 files changed, 87 insertions, 57 deletions
diff --git a/unix/tkUnixEvent.c b/unix/tkUnixEvent.c index 39e3e5e..4542876 100644 --- a/unix/tkUnixEvent.c +++ b/unix/tkUnixEvent.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixEvent.c,v 1.33 2010/01/01 22:50:27 dkf Exp $ + * RCS: @(#) $Id: tkUnixEvent.c,v 1.34 2010/01/02 11:07:56 dkf Exp $ */ #include "tkUnixInt.h" @@ -277,12 +277,15 @@ TransferXEventsToTcl( Display *display) { union { + int type; XEvent x; + TkKeyEvent k; #ifdef GenericEvent xGenericEvent xge; #endif } event; Window w; + TkDisplay *dispPtr = NULL; /* * Transfer events from the X event queue to the Tk event queue after XIM @@ -298,15 +301,13 @@ TransferXEventsToTcl( while (QLength(display) > 0) { XNextEvent(display, &event.x); #ifdef GenericEvent - if (event.x.type == GenericEvent) { + if (event.type == GenericEvent) { Tcl_Panic("Wild GenericEvent; panic! (extension=%d,evtype=%d)", event.xge.extension, event.xge.evtype); } #endif w = None; - if (event.x.type == KeyPress || event.x.type == KeyRelease) { - TkDisplay *dispPtr; - + if (event.type == KeyPress || event.type == KeyRelease) { for (dispPtr = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) { if (dispPtr == NULL) { break; @@ -321,6 +322,30 @@ TransferXEventsToTcl( if (XFilterEvent(&event.x, w)) { continue; } + if (event.type == KeyPress || event.type == KeyRelease) { + event.k.charValuePtr = NULL; + event.k.charValueLen = 0; + + /* + * Force the calling of the input method engine now. The results + * from it will be cached in the event so that they don't get lost + * (to a race condition with other XIM-handled key events) between + * entering the event queue and getting serviced. [Bug 1924761] + */ + +#ifdef TK_USE_INPUT_METHODS + if (event.type == KeyPress && dispPtr && + (dispPtr->flags & TK_DISPLAY_USE_IM)) { + if (dispPtr->focusPtr && dispPtr->focusPtr->inputContext) { + Tcl_DString ds; + + Tcl_DStringInit(&ds); + (void) TkpGetString(dispPtr->focusPtr, &event.x, &ds); + Tcl_DStringFree(&ds); + } + } +#endif + } Tk_QueueWindowEvent(&event.x, TCL_QUEUE_TAIL); } } diff --git a/unix/tkUnixKey.c b/unix/tkUnixKey.c index 49ee3e0..ef0588f 100644 --- a/unix/tkUnixKey.c +++ b/unix/tkUnixKey.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixKey.c,v 1.16 2009/12/16 22:00:30 nijtmans Exp $ + * RCS: @(#) $Id: tkUnixKey.c,v 1.17 2010/01/02 11:07:56 dkf Exp $ */ #include "tkInt.h" @@ -76,50 +76,6 @@ Tk_SetCaretPos( /* *---------------------------------------------------------------------- * - * TkpGetChar -- - * - * Convert a keyboard event to a UTF-8 string using XLookupString. - * - * This is used as a fallback instead of Xutf8LookupString or - * XmbLookupString if input methods are turned off and for KeyRelease - * events. - * - * Notes: - * XLookupString() normally returns a single ISO Latin 1 or ASCII control - * character. - * - *---------------------------------------------------------------------- - */ -static const char * -TkpGetChar( - XEvent *eventPtr, /* KeyPress or KeyRelease event */ - Tcl_DString *dsPtr) /* Initialized, empty string to hold result. */ -{ - int len; - char buf[TCL_DSTRING_STATIC_SIZE]; - - len = XLookupString(&eventPtr->xkey, buf, TCL_DSTRING_STATIC_SIZE, 0, 0); - buf[len] = '\0'; - - if (len == 1) { - len = Tcl_UniCharToUtf((unsigned char) buf[0], - Tcl_DStringValue(dsPtr)); - Tcl_DStringSetLength(dsPtr, len); - } else { - /* - * len > 1 should only happen if someone has called XRebindKeysym(). - * Assume UTF-8. - */ - - Tcl_DStringSetLength(dsPtr, len); - strncpy(Tcl_DStringValue(dsPtr), buf, len); - } - return Tcl_DStringValue(dsPtr); -} - -/* - *---------------------------------------------------------------------- - * * TkpGetString -- * * Retrieve the UTF string associated with a keyboard event. @@ -141,11 +97,25 @@ TkpGetString( XEvent *eventPtr, /* X keyboard event. */ Tcl_DString *dsPtr) /* Initialized, empty string to hold result. */ { + int len; + Tcl_DString buf; + TkKeyEvent *kePtr = (TkKeyEvent *) eventPtr; + + /* + * If we have the value cached already, use it now. [Bug 1373712] + */ + + if (kePtr->charValuePtr != NULL) { + Tcl_DStringSetLength(dsPtr, kePtr->charValueLen); + memcpy(Tcl_DStringValue(dsPtr), kePtr->charValuePtr, + (unsigned) kePtr->charValueLen+1); + return Tcl_DStringValue(dsPtr); + } + #ifdef TK_USE_INPUT_METHODS if ((winPtr->dispPtr->flags & TK_DISPLAY_USE_IM) && (winPtr->inputContext != NULL) && (eventPtr->type == KeyPress)) { - int len; Status status; #if X_HAVE_UTF8_STRING @@ -165,13 +135,10 @@ TkpGetString( NULL, &status); } if ((status != XLookupChars) && (status != XLookupBoth)) { - Tcl_DStringSetLength(dsPtr, 0); len = 0; } Tcl_DStringSetLength(dsPtr, len); #else /* !X_HAVE_UTF8_STRING */ - Tcl_DString buf; /* Holds string in system encoding. */ - /* * Overallocate the dstring to the maximum stack amount. */ @@ -198,11 +165,49 @@ TkpGetString( Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&buf), len, dsPtr); Tcl_DStringFree(&buf); #endif /* X_HAVE_UTF8_STRING */ + } else +#endif /* TK_USE_INPUT_METHODS */ + { + /* + * Fall back to convert a keyboard event to a UTF-8 string using + * XLookupString. This is used when input methods are turned off and + * for KeyRelease events. + * + * Note: XLookupString() normally returns a single ISO Latin 1 or + * ASCII control character. + */ - return Tcl_DStringValue(dsPtr); + Tcl_DStringInit(&buf); + Tcl_DStringSetLength(&buf, TCL_DSTRING_STATIC_SIZE-1); + len = XLookupString(&eventPtr->xkey, Tcl_DStringValue(&buf), + TCL_DSTRING_STATIC_SIZE, 0, 0); + Tcl_DStringValue(&buf)[len] = '\0'; + + if (len == 1) { + len = Tcl_UniCharToUtf((unsigned char) Tcl_DStringValue(&buf)[0], + Tcl_DStringValue(dsPtr)); + Tcl_DStringSetLength(dsPtr, len); + } else { + /* + * len > 1 should only happen if someone has called XRebindKeysym. + * Assume UTF-8. + */ + + Tcl_DStringSetLength(dsPtr, len); + strncpy(Tcl_DStringValue(dsPtr), Tcl_DStringValue(&buf), len); + } } -#endif /* TK_USE_INPUT_METHODS */ - return TkpGetChar(eventPtr, dsPtr); + + /* + * Cache the string in the event so that if/when we return to this + * function, we will be able to produce it without asking X. This stops us + * from having to reenter the XIM engine. [Bug 1373712] + */ + + kePtr->charValuePtr = ckalloc((unsigned) len + 1); + kePtr->charValueLen = len; + memcpy(kePtr->charValuePtr, Tcl_DStringValue(dsPtr), (unsigned) len + 1); + return Tcl_DStringValue(dsPtr); } /* |