/* * 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 */