--- tkUnixIm.c.orig Thu Feb 22 12:00:09 2001 +++ tkUnixIm.c Thu Feb 22 12:01:30 2001 @@ -0,0 +1,258 @@ +/* + * tkUnixIm.c -- + * + * This file contains modules to implement the XIM protocol session. + * This is the shrinked version of tkXIM.c, worte for tk8.0jp. + * + * + * Copyright 1999, 2000 Software Research Associates, Inc. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Software Research Associates not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. Software Research + * Associates makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied + * warranty. + */ + +#include "tkPort.h" +#include "tkInt.h" + +#ifdef TK_USE_INPUT_METHODS +#ifdef I18N_IMPROVE + +static void TkpIMGenericHandler _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); +static TkWindow * GetToplevel _ANSI_ARGS_((TkWindow *winPtr)); +static void TkpCreateIMGenericHandler _ANSI_ARGS_((Tk_Window tkwin)); +static void TkpDeleteIMGenericHandler _ANSI_ARGS_((Tk_Window tkwin)); + +static TkWindow * +GetToplevel(winPtr) + TkWindow *winPtr; +{ + while (!(winPtr->flags & TK_TOP_LEVEL)) { + winPtr = winPtr->parentPtr; + if (winPtr == NULL) { + return NULL; + } + } + return winPtr; +} + + +static void +TkpIMGenericHandler(clientData, eventPtr) + ClientData clientData; + XEvent *eventPtr; +{ + Tk_Window tkwin = (Tk_Window)clientData; + TkWindow *winPtr = (TkWindow *)clientData; + + if (eventPtr->xany.window != Tk_WindowId(tkwin) || + winPtr->inputContext == NULL || + !(winPtr->flags & TK_CHECKED_IC)) { + /* + * Why ME ??? + */ + return; + } + + /* + * Well, should I care about Enter/Leave ? + */ + + switch (eventPtr->type) { + case KeyPress: + case FocusIn: { + Window root, child; + int rootX, rootY; + int wX, wY; + unsigned int mask; + + /* + * Care about case mouse pointer is not on winPtr->window. + * In such a case, IM server can't fetch any events from Tk. + */ + + if (XQueryPointer(winPtr->display, + RootWindow(winPtr->display, winPtr->screenNum), + &root, &child, &rootX, &rootY, &wX, &wY, &mask) == True) { + TkWindow *pWin = (TkWindow *)Tk_CoordsToWindow(rootX, rootY, + (Tk_Window)winPtr); + if (pWin != NULL && (pWin->window != winPtr->window)) { +#if 0 + /* + * Code belows are what I REALLY want to do. But, + * in XIMPreeditPosition mode, IM server use the + * focus window as key event source window and as + * PreeditArea window by X11 specification. I want + * IM server to use this focus window ONLY as key + * event source. Means: + * + * o PreeditArea and PreeditPosition take place + * within client window (winPtr->window). + * o KeyPress event source is the window in which + * mouse pointer is (pWin->window). + */ + + if (XSetICValues(winPtr->inputContext, XNFocusWindow, + pWin->window, NULL) != NULL) { + fprintf(stderr, "debugIC: can't set IC focus to pointer window 0x%08x\n", + pWin->window); + } else { + fprintf(stderr, "debugIC: set IC focus to pointer window 0x%08x\n", + pWin->window); + } +#endif + /* + * Check pWin and winPtr are in same toplevel. + * If they are NOT, don't change focus. + */ + TkWindow *pTop = GetToplevel(pWin); + TkWindow *wTop = GetToplevel(winPtr); + if (pTop == wTop) { + TkpChangeFocus(winPtr, 1); + } + } + } + /* + * Get current focused window. + */ + if (winPtr->dispPtr->lastFocusedIC != winPtr->inputContext) { + winPtr->dispPtr->lastFocusedIC = winPtr->inputContext; + XSetICFocus(winPtr->inputContext); + } + break; + } + + case FocusOut: { + winPtr->dispPtr->lastFocusedIC = None; + XUnsetICFocus(winPtr->inputContext); + break; + } + + case DestroyNotify: { + winPtr->dispPtr->lastFocusedIC = NULL; + XUnsetICFocus(winPtr->inputContext); + TkpDeleteIMGenericHandler(tkwin); + break; + } + } +} + + +static void +TkpCreateIMGenericHandler(tkwin) + Tk_Window tkwin; +{ + Tk_CreateEventHandler(tkwin, FocusChangeMask|StructureNotifyMask|KeyPressMask +#if 0 + EnterWindowMask|LeaveWindowMask, +#else + , +#endif + (Tk_EventProc *)TkpIMGenericHandler, + (ClientData)tkwin); +} + + +static void +TkpDeleteIMGenericHandler(tkwin) + Tk_Window tkwin; +{ + Tk_DeleteEventHandler(tkwin, FocusChangeMask|StructureNotifyMask|KeyPressMask +#if 0 + EnterWindowMask|LeaveWindowMask, +#else + , +#endif + (Tk_EventProc *)TkpIMGenericHandler, + (ClientData)tkwin); +} + + +XIC +TkpCreateIC(winPtr) + TkWindow *winPtr; +{ + if (winPtr->dispPtr->inputMethod != NULL && + !(winPtr->flags & TK_CHECKED_IC)) { + winPtr->inputContext = + XCreateIC(winPtr->dispPtr->inputMethod, + XNInputStyle, XIMPreeditNothing|XIMStatusNothing, + XNClientWindow, winPtr->window, + XNFocusWindow, winPtr->window, + NULL); + if (winPtr->inputContext != NULL) { + TkpCreateIMGenericHandler((Tk_Window)winPtr); + } + } + winPtr->flags |= TK_CHECKED_IC; + return winPtr->inputContext; +} + + +void +TkpDestroyIC(winPtr, needDestroy) + TkWindow *winPtr; + int needDestroy; +{ + TkpDeleteIMGenericHandler((Tk_Window)winPtr); + if (winPtr->inputContext == winPtr->dispPtr->lastFocusedIC) { + winPtr->dispPtr->lastFocusedIC = None; + } + if (needDestroy == 1 && + winPtr->inputContext != NULL) { + XDestroyIC(winPtr->inputContext); + } + winPtr->flags &= ~(TK_CHECKED_IC); + winPtr->inputContext = NULL; +} + + +int +Tk_ImconfigureObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Main window associated with + * interpreter. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ +{ + Tk_Window tkwin = (Tk_Window)clientData; + Tcl_Obj *resultPtr = Tcl_GetObjResult(interp); + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "path ?option? ?arg? ..."); + return TCL_ERROR; + } + + tkwin = Tk_NameToWindow(interp, Tcl_GetStringFromObj(objv[1], NULL), tkwin); + if (tkwin == NULL) { + return TCL_ERROR; + } + + if (((TkWindow *)tkwin)->dispPtr->useInputMethods == 0) { + /* + * Destroy XIC and leave. + */ + TkpDestroyIC((TkWindow *)tkwin, 1); + return TCL_OK; + } + + if (((TkWindow *)tkwin)->dispPtr->inputMethod == NULL) { + Tcl_AppendStringsToObj(resultPtr, "No IM server is available.", NULL); + return TCL_ERROR; + } + + Tcl_AppendStringsToObj(resultPtr, + (TkpCreateIC((TkWindow *)tkwin) != NULL) ? "1" : "0", + NULL); + return TCL_OK; +} + +#endif /* I18N_IMPROVE */ +#endif /* TK_USE_INPUT_METHODS */