--- ../generic/tkWindow.c.orig Thu Dec 16 21:57:36 1999 +++ ../generic/tkWindow.c Wed Feb 21 23:20:48 2001 @@ -155,6 +155,9 @@ #ifdef MAC_TCL {"unsupported1", TkUnsupported1Cmd, NULL, 1, 1}, #endif +#if defined(TK_USE_INPUT_METHODS) && defined(I18N_IMPROVE) + {"imconfigure", NULL, Tk_ImconfigureObjCmd, 1, 1}, +#endif /* TK_USE_INPUT_METHODS && I18N_IMPROVE */ {(char *) NULL, (int (*) _ANSI_ARGS_((ClientData, Tcl_Interp *, int, char **))) NULL, NULL, 0} }; @@ -209,6 +212,15 @@ char *name)); static void OpenIM _ANSI_ARGS_((TkDisplay *dispPtr)); static void UnlinkWindow _ANSI_ARGS_((TkWindow *winPtr)); +#ifdef TK_USE_INPUT_METHODS +#ifdef I18N_IMPROVE +static int CanInitiateIm _ANSI_ARGS_((void)); +static void IMInstantiateCallback _ANSI_ARGS_ ((Display *display, + XPointer clientData, XPointer callData)); +static void IMDestroyCallback _ANSI_ARGS_ ((XIM im, XPointer clientData, + XPointer callData)); +#endif /* I18N_IMPROVE */ +#endif /* TK_USE_INPUT_METHODS */ /* *---------------------------------------------------------------------- @@ -631,6 +643,9 @@ winPtr->handlerList = NULL; #ifdef TK_USE_INPUT_METHODS winPtr->inputContext = NULL; +#ifdef I18N_IMPROVE + Tcl_DStringInit(&(winPtr->composedDStr)); +#endif /* I18N_IMPROVE */ #endif /* TK_USE_INPUT_METHODS */ winPtr->tagPtr = NULL; winPtr->numTags = 0; @@ -1275,8 +1290,16 @@ TkBindDeadWindow(winPtr); #ifdef TK_USE_INPUT_METHODS if (winPtr->inputContext != NULL) { - XDestroyIC(winPtr->inputContext); +#ifdef I18N_IMPROVE + TkpDestroyIC(winPtr, 1); +#else + XDestroyIC(winPtr->inputContext); +#endif /* I18N_IMPROVE */ } +#ifdef I18N_IMPROVE + Tcl_DStringFree(&(winPtr->composedDStr)); + Tcl_DStringInit(&(winPtr->composedDStr)); +#endif /* I18N_IMPROVE */ #endif /* TK_USE_INPUT_METHODS */ if (winPtr->tagPtr != NULL) { TkFreeBindingTags(winPtr); @@ -2427,6 +2450,180 @@ { return ((TkWindow *) tkwin)->mainPtr->strictMotif; } +#ifdef TK_USE_INPUT_METHODS +#ifdef I18N_IMPROVE + +static int +CanInitiateIm() +{ + static int inited = 0; + static int ret = 0; + char *locale; + + /* + * Determine the current encoding from the LC_* or LANG environment + * variables. We previously used setlocale() to determine the locale, + * but this does not work on some systems (e.g. Linux/i386 RH 5.0). + */ + + locale = getenv("LC_ALL"); + + if (locale == NULL || locale[0] == '\0') { + locale = getenv("LC_CTYPE"); + } + if (locale == NULL || locale[0] == '\0') { + locale = getenv("LANG"); + } + if (locale == NULL || locale[0] == '\0') { + return False; + } + + if (inited == 0) { + char *curSpec = setlocale(LC_ALL, NULL); + + inited = 1; + + if (strcmp(locale, "C") == 0 || + strcmp(locale, "POSIX") == 0) { + goto Checked; + } + + /* + * setlocale(3)/_Xsetlocale() VERY HERE. This is what the X + * input method wants. + * Note that X11's i18n implementation should be ONLY governed + * by LC_CTYPE. This is clearly/explicitly specified in X11 + * documente Chapter 13. Thus, If there are some X11 + * implementation that need using LC_ALL to initialize i18n + * subsystem, I won't care about such a X library. + * But, we are still on edge of darkside. ctype(3) routines + * are governed by LC_CTYPE.... Need to create "Locale + * independent ctype libraries" for Tcl/Tk... + * + */ + + /* + * OK, First of all, setting WHOLE locale to "C". + */ + (void)setlocale(LC_ALL, "C"); + if (setlocale(LC_CTYPE, locale) == NULL) { + /* + * Reset to old locale. + */ + if (setlocale(LC_ALL, curSpec) == NULL) { + (void)setlocale(LC_ALL, "C"); + } + goto Checked; + } else { + /* + * For insurance, reset LC_NUMERIC to "C" for Tcl numeric parsing. + */ + (void)setlocale(LC_NUMERIC, "C"); + } + if (XSupportsLocale() != True) { + goto Checked; + } + + ret = True; + /* + * At last, Setting the locale modifiers. + */ + (void)XSetLocaleModifiers(""); + } + + Checked: + return ret; +} + +/* + *---------------------------------------------------------------------- + * + * IMInstantiateCallback + * + * Whenever IM server become available, this function will be called. + * + * Results: + * OpenIM() is called. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +IMInstantiateCallback(display, clientData, callData) + Display *display; + XPointer clientData; + XPointer callData; +{ + TkDisplay *dispPtr = (TkDisplay *)clientData; + + if (display == dispPtr->display && + dispPtr->inputMethod == NULL) { + OpenIM(dispPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * IMDestroyCallback + * + * Whenever IM server stops the service, this function will be called. + * + * Results: + * the XIM opened before is marked as unusable. + * + * Side effects: + * XIC using this XIM will be useless. + * + *---------------------------------------------------------------------- + */ +void +IMDestroyCallback(im, clientData, callData) + XIM im; + XPointer clientData; + XPointer callData; +{ + TkDisplay *dispPtr = (TkDisplay *)clientData; + if (im == dispPtr->inputMethod) { + Tcl_HashTable winTable = dispPtr->winTable; + Tcl_HashEntry *entry = NULL; + Tcl_HashSearch search; + TkWindow *winPtr; + + /* + * We must not call XCloseIM() or XDestroyIC(). + * because the XIM and XIC are destroyed by Xlib + * automatically. + */ + for (entry = Tcl_FirstHashEntry(&winTable, &search); entry != NULL; + entry = Tcl_NextHashEntry(&search)) { + winPtr = (TkWindow *)Tcl_GetHashValue(entry); + if (winPtr->dispPtr->display == dispPtr->display && + winPtr->dispPtr->inputMethod == im && + winPtr->inputContext != NULL) { + TkpDestroyIC(winPtr, 0); + } + Tcl_DStringFree(&(winPtr->composedDStr)); + Tcl_DStringInit(&(winPtr->composedDStr)); + } + dispPtr->inputMethod = NULL; + dispPtr->lastFocusedIC = NULL; +#ifdef HAVE_XIMREGINSTCB +#ifdef NO_XIDPROC + XRegisterIMInstantiateCallback(dispPtr->display, NULL, NULL, NULL, + (XIMProc)IMInstantiateCallback, (XPointer *)dispPtr); +#else + XRegisterIMInstantiateCallback(dispPtr->display, NULL, NULL, NULL, + (XIDProc)IMInstantiateCallback, (XPointer)dispPtr); +#endif /* NO_XIDPROC */ +#endif /* HAVE_XIMREGINSTCB */ + } +} +#endif /* I18N_IMPROVE */ +#endif /* TK_USE_INPUT_METHODS */ /* *-------------------------------------------------------------- @@ -2457,8 +2654,35 @@ unsigned short i; XIMStyles *stylePtr; +#ifdef I18N_IMPROVE + int styleFound = 0; + + dispPtr->inputMethod = NULL; + dispPtr->imEncoding = NULL; + dispPtr->lastFocusedIC = NULL; + dispPtr->isComposed = 0; + + if (CanInitiateIm() == False) { + return; + } +#endif /* I18N_IMPROVE */ dispPtr->inputMethod = XOpenIM(dispPtr->display, NULL, NULL, NULL); if (dispPtr->inputMethod == NULL) { +#ifdef I18N_IMPROVE +#ifdef HAVE_XIMREGINSTCB + /* + * Maybe no IM server is available right now. + * Try to register instantiate callback. + */ +#ifdef NO_XIDPROC + XRegisterIMInstantiateCallback(dispPtr->display, NULL, NULL, NULL, + (XIMProc)IMInstantiateCallback, (XPointer *)dispPtr); +#else + XRegisterIMInstantiateCallback(dispPtr->display, NULL, NULL, NULL, + (XIDProc)IMInstantiateCallback, (XPointer)dispPtr); +#endif /* NO_XIDPROC */ +#endif /* HAVE_XIMREGINSTCB */ +#endif /* I18N_IMPROVE */ return; } @@ -2469,11 +2693,30 @@ for (i = 0; i < stylePtr->count_styles; i++) { if (stylePtr->supported_styles[i] == (XIMPreeditNothing|XIMStatusNothing)) { - XFree(stylePtr); - return; +#ifdef I18N_IMPROVE + styleFound = 1; +#else + XFree(stylePtr); + return; +#endif /* I18N_IMPROVE */ } } XFree(stylePtr); +#ifdef I18N_IMPROVE + if (styleFound == 1) { + /* + * Create a Tcl_Encoding for XmbLookupString() conversion. + */ + dispPtr->imEncoding = Tcl_GetEncoding(NULL, Tcl_GetEncodingName(NULL)); +#ifdef XNDestroyCallback + dispPtr->destroyCallback.client_data = (XPointer)dispPtr; + dispPtr->destroyCallback.callback = (XIMProc)IMDestroyCallback; + (void)XSetIMValues(dispPtr->inputMethod, + XNDestroyCallback, &(dispPtr->destroyCallback), NULL); +#endif /* XNDestroyCallback */ + return; + } +#endif /* I18N_IMPROVE */ error: