Path: blob/master/src/java.desktop/aix/native/libawt_xawt/awt/awt_InputMethod.c
41152 views
/*1* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#ifdef HEADLESS26#error This file should not be included in headless library27#endif2829#include "awt.h"30#include "awt_p.h"3132#include <sun_awt_X11InputMethodBase.h>33#include <sun_awt_X11InputMethod.h>34#include <sun_awt_X11_XInputMethod.h>3536#include <langinfo.h>37#include <stdio.h>38#include <stdlib.h>39#include <sys/time.h>40#include <wchar.h>41#include <wctype.h>42#include <X11/Intrinsic.h>43#include <X11/keysym.h>44#include <X11/Xlib.h>4546#define THROW_OUT_OF_MEMORY_ERROR() \47JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL)4849struct X11InputMethodIDs {50jfieldID pData;51} x11InputMethodIDs;5253static int PreeditStartCallback(XIC, XPointer, XPointer);54static void PreeditDoneCallback(XIC, XPointer, XPointer);55static void PreeditDrawCallback(XIC, XPointer,56XIMPreeditDrawCallbackStruct *);57static void PreeditCaretCallback(XIC, XPointer,58XIMPreeditCaretCallbackStruct *);59static void StatusStartCallback(XIC, XPointer, XPointer);60static void StatusDoneCallback(XIC, XPointer, XPointer);61static void StatusDrawCallback(XIC, XPointer,62XIMStatusDrawCallbackStruct *);6364#define ROOT_WINDOW_STYLES (XIMPreeditNothing | XIMStatusNothing)65#define NO_STYLES (XIMPreeditNone | XIMStatusNone)66/* added style to allow for in-place composition, such as "dead" keys for accents */67#define IN_PLACE_STYLES (XIMPreeditNothing | XIMStatusNone)6869#define PreeditStartIndex 070#define PreeditDoneIndex 171#define PreeditDrawIndex 272#define PreeditCaretIndex 373#define StatusStartIndex 474#define StatusDoneIndex 575#define StatusDrawIndex 676#define NCALLBACKS 77778#define STATUS_BORDER 2 /* Status Border width */79#define CARET_OFFSET 1 /* Offset of caret position (pixel) */80#define BORDER_MARGIN 3 /* BORDER MARGIN width */81#define STATUS_MARGIN 7 /* Margin between the status window and its parent window */82#define PREEDIT_ATTR_MASK (XIMReverse|XIMUnderline)83/* Preedit attribute which host adapter can handle */8485/*86* Callback function pointers: the order has to match the *Index87* values above.88*/89static XIMProc callback_funcs[NCALLBACKS] = {90(XIMProc)(void *)&PreeditStartCallback,91(XIMProc)PreeditDoneCallback,92(XIMProc)PreeditDrawCallback,93(XIMProc)PreeditCaretCallback,94(XIMProc)StatusStartCallback,95(XIMProc)StatusDoneCallback,96(XIMProc)StatusDrawCallback,97};9899#define MAX_STATUS_LEN 100100typedef struct {101Window w; /*status window id */102Window root; /*the root window id */103Window parent; /*parent shell window */104Window grandParent; /*window has WM frame */105int x, y; /*parent's upperleft position */106int width, height; /*parent's width, height */107GC lightGC; /*gc for light border */108GC dimGC; /*gc for dim border */109GC bgGC; /*normal painting */110GC fgGC; /*normal painting */111int statusW, statusH; /*status window's w, h */112int rootW, rootH; /*root window's w, h */113int bWidth; /*border width */114wchar_t status[MAX_STATUS_LEN + 1]; /*status text */115XFontSet fontset; /*fontset for drawing */116int off_x, off_y;117Bool on; /*if the status window on*/118int fOff; /* font base line(in pixel) from top */119int fBot; /* font bottom line(in pixel) from top */120int peTextW; /* Composition text width in pixel */121wchar_t* peText; /* Composed string (wide char.) */122XIMFeedback* peAttr; /* Composed text attribute */123int peCaret; /* Caret position in number of character */124Bool status_ready; /* Not draw Status at XCreateIC */125} StatusWindow;126127/*128* X11InputMethodData keeps per X11InputMethod instance information. A pointer129* to this data structure is kept in an X11InputMethod object (pData).130*/131typedef struct _X11InputMethodData {132XIC current_ic; /* current X Input Context */133XIC ic_active; /* X Input Context for active clients */134XIC ic_passive; /* X Input Context for passive clients */135XIMCallback *callbacks; /* callback parameters */136jobject x11inputmethod; /* global ref to X11InputMethod instance */137/* associated with the XIC */138StatusWindow *statusWindow; /* our own status window */139Bool passiveStatusWindow;/* Passive Client uses StatusWindow */140Bool isActiveClient; /* True:clinet is active */141Bool forceReset; /* True: call resetXIC before UnsetICFocus */142} X11InputMethodData;143144/* reference to the current X11InputMethod instance, it is always145point to the global reference to the X11InputMethodObject since146it could be referenced by different threads. */147jobject currentX11InputMethodInstance = NULL;148149Window currentFocusWindow = 0; /* current window that has focus for input150method. (the best place to put this151information should be152currentX11InputMethodInstance's pData) */153static XIM X11im = NULL;154Display * dpy = NULL;155156#define GetJNIEnv() (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2)157158static X11InputMethodData * getX11InputMethodData(JNIEnv *, jobject);159static void setX11InputMethodData(JNIEnv *, jobject, X11InputMethodData *);160static void destroyX11InputMethodData(JNIEnv *, X11InputMethodData *);161static void freeX11InputMethodData(JNIEnv *, X11InputMethodData *);162163/* Prototype for this function is missing in AIX Xlib.h */164extern char *XSetIMValues(165#if NeedVarargsPrototypes166XIM /* im */, ...167#endif168);169170static int st_wcslen(wchar_t *string);171static Bool isPreeditStateActive(XIC ic);172static void * buf_insert(void * src, void * insert, int size,173int src_len, int ins_len, int offset);174static void * handle_buffer(void * source, void * insert,175int size, int src_len, int ins_len,176int del_len, int offset);177static void preedit_draw_passive(X11InputMethodData *pX11IMData,178XIMPreeditDrawCallbackStruct *pre_draw);179static void resetPassivePreeditText(StatusWindow *statusWindow);180static void draw_caret(StatusWindow *statusWindow, GC gc, int pos);181static int get_next_attr(int len, unsigned long *attr);182static void draw_preedit(StatusWindow *statusWindow);183static void align_status(StatusWindow *statusWindow);184static void shrink_status(StatusWindow *statusWindow);185static XFontSet create_fontset(void);186static Bool is_text_available(XIMText * text);187static Bool isNativeIm();188static Window getGrandParent(Window parent);189static void moveStatusWindow(StatusWindow *statusWindow);190static void arrange_window_stack(StatusWindow* statusWindow);191static Window get_current_focus(XIC ic);192193/*194* This function is stolen from /src/solaris/hpi/src/system_md.c195* It is used in setting the time in Java-level InputEvents196*/197jlong198awt_util_nowMillisUTC()199{200struct timeval t;201gettimeofday(&t, NULL);202return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000);203}204205/*206* Converts the wchar_t string to a multi-byte string calling wcstombs(). A207* buffer is allocated by malloc() to store the multi-byte string. NULL is208* returned if the given wchar_t string pointer is NULL or buffer allocation is209* failed.210*/211static char *212wcstombsdmp(wchar_t *wcs, int len)213{214size_t n;215char *mbs;216217if (wcs == NULL)218return NULL;219220n = len*MB_CUR_MAX + 1;221222mbs = (char *) malloc(n * sizeof(char));223if (mbs == NULL) {224THROW_OUT_OF_MEMORY_ERROR();225return NULL;226}227228/* TODO: check return values... Handle invalid characters properly... */229if (wcstombs(mbs, wcs, n) == (size_t)-1) {230free(mbs);231return NULL;232}233234return mbs;235}236237static X11InputMethodData * getX11InputMethodData(JNIEnv * env, jobject imInstance) {238X11InputMethodData *pX11IMData =239(X11InputMethodData *)JNU_GetLongFieldAsPtr(env, imInstance, x11InputMethodIDs.pData);240241/*242* In case the XIM server was killed somehow, reset X11InputMethodData.243*/244if (X11im == NULL && pX11IMData != NULL) {245JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,246"flushText",247"()V");248JNU_CHECK_EXCEPTION_RETURN(env, NULL);249/* IMPORTANT:250The order of the following calls is critical since "imInstance" may251point to the global reference itself, if "freeX11InputMethodData" is called252first, the global reference will be destroyed and "setX11InputMethodData"253will in fact fail silently. So pX11IMData will not be set to NULL.254This could make the original java object refers to a deleted pX11IMData255object.256*/257setX11InputMethodData(env, imInstance, NULL);258freeX11InputMethodData(env, pX11IMData);259pX11IMData = NULL;260}261262return pX11IMData;263}264265static void setX11InputMethodData(JNIEnv * env, jobject imInstance, X11InputMethodData *pX11IMData) {266JNU_SetLongFieldFromPtr(env, imInstance, x11InputMethodIDs.pData, pX11IMData);267}268269/* this function should be called within AWT_LOCK() */270static void271destroyX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData)272{273/*274* Destroy XICs275*/276if (pX11IMData == NULL) {277return;278}279280if (pX11IMData->ic_active != (XIC)0) {281XUnsetICFocus(pX11IMData->ic_active);282XDestroyIC(pX11IMData->ic_active);283if (pX11IMData->ic_active != pX11IMData->ic_passive) {284if (pX11IMData->ic_passive != (XIC)0) {285XUnsetICFocus(pX11IMData->ic_passive);286XDestroyIC(pX11IMData->ic_passive);287}288pX11IMData->ic_passive = (XIC)0;289pX11IMData->current_ic = (XIC)0;290}291}292293freeX11InputMethodData(env, pX11IMData);294}295296static void297freeX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData)298{299if (pX11IMData->statusWindow != NULL){300StatusWindow *sw = pX11IMData->statusWindow;301XFreeGC(awt_display, sw->lightGC);302XFreeGC(awt_display, sw->dimGC);303XFreeGC(awt_display, sw->bgGC);304XFreeGC(awt_display, sw->fgGC);305if (sw->fontset != NULL) {306XFreeFontSet(awt_display, sw->fontset);307}308XDestroyWindow(awt_display, sw->w);309if (pX11IMData->statusWindow->peText){310free((void *)pX11IMData->statusWindow->peText);311pX11IMData->statusWindow->peText = NULL;312}313if (pX11IMData->statusWindow->peAttr){314free((void *)pX11IMData->statusWindow->peAttr);315pX11IMData->statusWindow->peAttr = NULL;316}317free((void*)sw);318}319320if (pX11IMData->callbacks)321free((void *)pX11IMData->callbacks);322323if (env) {324(*env)->DeleteGlobalRef(env, pX11IMData->x11inputmethod);325}326327free((void *)pX11IMData);328}329330/*331* Sets or unsets the focus to the given XIC.332*/333static void334setXICFocus(XIC ic, unsigned short req)335{336if (ic == NULL) {337(void)fprintf(stderr, "Couldn't find X Input Context\n");338return;339}340if (req == 1)341XSetICFocus(ic);342else343XUnsetICFocus(ic);344}345346/*347* Sets the focus window to the given XIC.348*/349static void350setXICWindowFocus(XIC ic, Window w)351{352if (ic == NULL) {353(void)fprintf(stderr, "Couldn't find X Input Context\n");354return;355}356(void) XSetICValues(ic, XNFocusWindow, w, NULL);357}358359/*360* Invokes XmbLookupString() to get something from the XIM. It invokes361* X11InputMethod.dispatchCommittedText() if XmbLookupString() returns362* committed text. This function is called from handleKeyEvent in canvas.c and363* it's under the Motif event loop thread context.364*365* Buffer usage: There is a bug in XFree86-4.3.0 XmbLookupString implementation,366* where it never returns XBufferOverflow. We need to allocate the initial lookup buffer367* big enough, so that the possibility that user encounters this problem is relatively368* small. When this bug gets fixed, we can make the initial buffer size smaller.369* Note that XmbLookupString() sometimes produces a non-null-terminated string.370*371* Returns True when there is a keysym value to be handled.372*/373#define INITIAL_LOOKUP_BUF_SIZE 512374375Boolean376awt_x11inputmethod_lookupString(XKeyPressedEvent *event, KeySym *keysymp)377{378JNIEnv *env = GetJNIEnv();379X11InputMethodData *pX11IMData = NULL;380int buf_len = INITIAL_LOOKUP_BUF_SIZE;381char mbbuf[INITIAL_LOOKUP_BUF_SIZE];382char *buf;383KeySym keysym = NoSymbol;384Status status;385int mblen;386jstring javastr;387XIC ic;388Boolean result = True;389static Boolean composing = False;390391/*392printf("lookupString: entering...\n");393*/394395pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);396397if (pX11IMData == NULL) {398return False;399}400401if ((ic = pX11IMData->current_ic) == (XIC)0){402return False;403}404405buf = mbbuf;406mblen = XmbLookupString(ic, event, buf,407buf_len - 1, &keysym, &status);408409/*410* In case of overflow, a buffer is allocated and it retries411* XmbLookupString().412*/413if (status == XBufferOverflow) {414buf_len = mblen + 1;415buf = (char *)malloc(buf_len);416if (buf == NULL) {417THROW_OUT_OF_MEMORY_ERROR();418return result;419}420mblen = XmbLookupString(ic, event, buf, buf_len, &keysym, &status);421}422buf[mblen] = 0;423424/* Get keysym without taking modifiers into account first to map425* to AWT keyCode table.426*/427switch (status) {428case XLookupBoth:429if (!composing) {430if (event->keycode != 0) {431*keysymp = keysym;432result = False;433break;434}435}436composing = False;437/*FALLTHRU*/438case XLookupChars:439/*440printf("lookupString: status=XLookupChars, type=%d, state=%x, keycode=%x, keysym=%x\n",441event->type, event->state, event->keycode, keysym);442*/443javastr = JNU_NewStringPlatform(env, (const char *)buf);444if (javastr != NULL) {445JNU_CallMethodByName(env, NULL,446currentX11InputMethodInstance,447"dispatchCommittedText",448"(Ljava/lang/String;J)V",449javastr,450event->time);451if ((*env)->ExceptionOccurred(env)) {452(*env)->ExceptionDescribe(env);453(*env)->ExceptionClear(env);454}455}456break;457458case XLookupKeySym:459/*460printf("lookupString: status=XLookupKeySym, type=%d, state=%x, keycode=%x, keysym=%x\n",461event->type, event->state, event->keycode, keysym);462*/463if (keysym == XK_Multi_key)464composing = True;465if (! composing) {466*keysymp = keysym;467result = False;468}469break;470471case XLookupNone:472/*473printf("lookupString: status=XLookupNone, type=%d, state=%x, keycode=%x, keysym=%x\n",474event->type, event->state, event->keycode, keysym);475*/476break;477}478479if (buf != mbbuf) {480free(buf);481}482return result;483}484485static StatusWindow *createStatusWindow(Window parent) {486StatusWindow *statusWindow;487XSetWindowAttributes attrib;488unsigned long attribmask;489Window containerWindow;490Window status;491Window child;492XWindowAttributes xwa;493XWindowAttributes xxwa;494/* Variable for XCreateFontSet()*/495char **mclr;496int mccr = 0;497char *dsr;498unsigned long bg, fg, light, dim;499int x, y, off_x, off_y, xx, yy;500unsigned int w, h, bw, depth;501XGCValues values;502unsigned long valuemask = 0; /*ignore XGCvalue and use defaults*/503int screen = 0;504int i;505AwtGraphicsConfigDataPtr adata;506extern int awt_numScreens;507/*hardcode the size right now, should get the size base on font*/508int width=80, height=22;509Window rootWindow;510Window *ignoreWindowPtr;511unsigned int ignoreUnit;512Window grandParent;513Window target;514XFontSet fontset;515516fontset = create_fontset();517if (NULL == fontset) {518return NULL;519}520521XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth);522523attrib.override_redirect = True;524attribmask = CWOverrideRedirect;525for (i = 0; i < awt_numScreens; i++) {526if (RootWindow(dpy, i) == rootWindow) {527screen = i;528break;529}530}531adata = getDefaultConfig(screen);532bg = adata->AwtColorMatch(255, 255, 255, adata);533fg = adata->AwtColorMatch(0, 0, 0, adata);534light = adata->AwtColorMatch(195, 195, 195, adata);535dim = adata->AwtColorMatch(128, 128, 128, adata);536537grandParent = getGrandParent(parent);538target = (grandParent == 0) ? parent : grandParent;539XGetWindowAttributes(dpy, target, &xwa);540bw = 2; /*xwa.border_width does not have the correct value*/541542/*compare the size difference between parent container543and shell widget, the diff should be the border frame544and title bar height (?)*/545546XQueryTree( dpy,547target,548&rootWindow,549&containerWindow,550&ignoreWindowPtr,551&ignoreUnit);552XGetWindowAttributes(dpy, containerWindow, &xxwa);553554XTranslateCoordinates(dpy,555target, xwa.root,5560, 0,557&x, &y, &child);558559if (containerWindow == rootWindow) {560off_x = 0; off_y = STATUS_MARGIN;561} else {562XGetWindowAttributes(dpy, containerWindow, &xxwa);563off_x = (xxwa.width - xwa.width) / 2;564/* off_y = xxwa.height - xwa.height - off_x;*/ /*it's magic:-) */565{566int cx, cy;567XTranslateCoordinates(dpy,568containerWindow, xxwa.root,5690, 0,570&cx, &cy,571&child);572off_y = (xxwa.height + cy) - (xwa.height + y);573}574}575576/*get the size of root window*/577XGetWindowAttributes(dpy, rootWindow, &xxwa);578579XTranslateCoordinates(dpy,580target, xwa.root,581xwa.x, xwa.y,582&x, &y,583&child);584xx = x - off_x;585yy = y + xwa.height - off_y;586if (xx < 0 ){587xx = 0;588}589if (xx + width > xxwa.width) {590xx = xxwa.width - width;591}592if (yy + height > xxwa.height) {593yy = xxwa.height - height;594}595596if ((DefaultVisual(dpy,screen))->class != adata->awt_visInfo.visual->class &&597adata->awt_visInfo.visual->class == TrueColor) {598attrib.colormap = XCreateColormap(dpy, xwa.root,599adata->awt_visInfo.visual, AllocNone );600attrib.border_pixel = BlackPixel(dpy, screen) ;601attribmask |= CWColormap | CWBorderPixel;602}603604status = XCreateWindow(dpy,605xwa.root,606xx, yy,607width, height,6080,609xwa.depth,610InputOutput,611adata->awt_visInfo.visual,612attribmask, &attrib);613XSelectInput(dpy, status,614ExposureMask | StructureNotifyMask | EnterWindowMask |615LeaveWindowMask | VisibilityChangeMask);616if (grandParent != 0){617long mask;618XGetWindowAttributes(dpy, grandParent, &xwa);619mask = xwa.your_event_mask | StructureNotifyMask |620VisibilityChangeMask | PropertyChangeMask;621XSelectInput(dpy, grandParent,mask);622}623624statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow));625if (statusWindow == NULL){626THROW_OUT_OF_MEMORY_ERROR();627return NULL;628}629statusWindow->w = status;630statusWindow->fontset = fontset;631statusWindow->parent = parent;632statusWindow->grandParent = grandParent;633statusWindow->on = False;634statusWindow->x = x;635statusWindow->y = y;636statusWindow->width = xwa.width;637statusWindow->height = xwa.height;638statusWindow->off_x = off_x;639statusWindow->off_y = off_y;640statusWindow->bWidth = bw;641statusWindow->statusH = height;642statusWindow->statusW = width;643statusWindow->peTextW = 0;644statusWindow->rootH = xxwa.height;645statusWindow->rootW = xxwa.width;646statusWindow->lightGC = XCreateGC(dpy, status, valuemask, &values);647XSetForeground(dpy, statusWindow->lightGC, light);648statusWindow->dimGC = XCreateGC(dpy, status, valuemask, &values);649XSetForeground(dpy, statusWindow->dimGC, dim);650statusWindow->fgGC = XCreateGC(dpy, status, valuemask, &values);651XSetForeground(dpy, statusWindow->fgGC, fg);652XSetBackground(dpy, statusWindow->fgGC, bg);653statusWindow->bgGC = XCreateGC(dpy, status, valuemask, &values);654XSetForeground(dpy, statusWindow->bgGC, bg);655XSetBackground(dpy, statusWindow->bgGC, fg);656statusWindow->status_ready = False;657wcscpy(statusWindow->status, L"");658return statusWindow;659}660661/* This method is to turn off or turn on the status window. */662static void onoffStatusWindow(X11InputMethodData* pX11IMData,663Window parent,664Bool ON){665XWindowAttributes xwa;666Window child;667int x, y;668StatusWindow *statusWindow = NULL;669670if (NULL == pX11IMData ||671NULL == (statusWindow = pX11IMData->statusWindow)){672return;673}674675if (ON == False) {676XUnmapWindow(dpy, statusWindow->w);677return;678}679if (NULL == currentX11InputMethodInstance){680return;681}682{683JNIEnv *env = GetJNIEnv();684parent = JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,685"getCurrentParentWindow",686"()J").j;687if ((*env)->ExceptionOccurred(env)) {688(*env)->ExceptionDescribe(env);689(*env)->ExceptionClear(env);690}691}692if (statusWindow->parent != parent) {693statusWindow->parent = parent;694}695if (st_wcslen(statusWindow->status) > 0 ||696(statusWindow->peText != NULL && st_wcslen(statusWindow->peText) > 0 )) {697moveStatusWindow(statusWindow);698XMapRaised(dpy, statusWindow->w);699}700}701702void paintStatusWindow(StatusWindow *statusWindow){703Window win = statusWindow->w;704GC lightgc = statusWindow->lightGC;705GC dimgc = statusWindow->dimGC;706GC bggc = statusWindow->bgGC;707GC fggc = statusWindow->fgGC;708709int width = statusWindow->statusW;710int height = statusWindow->statusH;711int bwidth = statusWindow->bWidth;712int len;713XRectangle logical, ink;714715if (NULL == statusWindow) return;716if ((len = st_wcslen(statusWindow->status)) == 0) {717return;718}719XwcTextExtents(statusWindow->fontset, statusWindow->status,720len, &ink, &logical);721width = logical.width;722height = logical.height;723724XFillRectangle(dpy, win, bggc, 0, 0, width+2, height+2);725726XDrawLine(dpy, win, fggc, 0, 0, width+2, 0);727XDrawLine(dpy, win, fggc, 0, height+2, width+2, height+2);728XDrawLine(dpy, win, fggc, 0, 0, 0, height+2);729XDrawLine(dpy, win, fggc, width+2, 0, width+2, height+2);730731if (statusWindow->fontset) {732XwcDrawString(dpy, win, statusWindow->fontset, fggc,733-logical.x + 1, -logical.y + 1,734statusWindow->status,735st_wcslen(statusWindow->status));736} else {737/*too bad we failed to create a fontset for this locale*/738XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4,739"[InputMethod ON]", strlen("[InputMethod ON]"));740}741}742743Bool statusWindowEventHandler(XEvent event) {744JNIEnv *env = GetJNIEnv();745X11InputMethodData *pX11IMData = NULL;746StatusWindow *statusWindow;747748if (NULL == currentX11InputMethodInstance ||749NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance)) ||750NULL == (statusWindow = pX11IMData->statusWindow))751{752return False;753}754755if (statusWindow->w == event.xany.window) {756switch (event.type) {757case Expose:758paintStatusWindow(statusWindow);759if (statusWindow->peText)760draw_preedit(statusWindow);761arrange_window_stack(statusWindow);762break;763case ConfigureNotify:764case VisibilityNotify:765arrange_window_stack(statusWindow);766break;767/*768case UnmapNotify:769case VisibilityNotify:770break;771*/772default:773break;774}775return True;776} else if ((statusWindow->parent == event.xany.window) ||777(statusWindow->grandParent && statusWindow->grandParent == event.xany.window)) {778switch (event.type) {779case MapNotify:780if (statusWindow->on) {781onoffStatusWindow(pX11IMData, statusWindow->parent, True);782}783break;784case UnmapNotify:785onoffStatusWindow(pX11IMData, 0, False);786break;787case VisibilityNotify:788if (statusWindow->on) {789arrange_window_stack(statusWindow);790}791break;792case ConfigureNotify:793if (statusWindow->grandParent && statusWindow->on) {794moveStatusWindow(statusWindow);795}796case PropertyNotify:797if (statusWindow->on) {798arrange_window_stack(statusWindow);799}800break;801default:802break;803}804}805return False;806}807808static void adjustStatusWindow(Window shell) {809JNIEnv *env = GetJNIEnv();810X11InputMethodData *pX11IMData = NULL;811StatusWindow *statusWindow;812813if (NULL == currentX11InputMethodInstance814|| NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))815|| NULL == (statusWindow = pX11IMData->statusWindow)816|| !statusWindow->on)817{818return;819}820821moveStatusWindow(statusWindow);822}823824/*825* Creates two XICs, one for active clients and the other for passive826* clients. All information on those XICs are stored in the827* X11InputMethodData given by the pX11IMData parameter.828*829* For active clients: Try to use preedit callback to support830* on-the-spot. If tc is not null, the XIC to be created will831* share the Status Area with Motif widgets (TextComponents). If the832* preferable styles can't be used, fallback to root-window styles. If833* root-window styles failed, fallback to None styles.834*835* For passive clients: Try to use root-window styles. If failed,836* fallback to None styles.837*/838static Bool839createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w)840{841XVaNestedList preedit = NULL;842XVaNestedList status = NULL;843XIMStyle on_the_spot_styles = XIMPreeditCallbacks,844in_place_styles = 0,845active_styles = 0,846passive_styles = 0,847no_styles = 0;848XIMCallback *callbacks;849unsigned short i;850XIMStyles *im_styles;851char *ret = NULL;852Bool passiveStatusWindow = False;853pX11IMData->statusWindow = NULL;854855if (X11im == NULL) {856return False;857}858if (!w) {859return False;860}861862if (getenv("IBMJAVA_PASSIVE") == NULL) {863passiveStatusWindow = False;864} else {865passiveStatusWindow = True;866}867868if (isNativeIm()) { passiveStatusWindow = True; }869870ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL);871872if (ret != NULL) {873jio_fprintf(stderr,"XGetIMValues: %s\n",ret);874return FALSE ;875}876877on_the_spot_styles |= XIMStatusNothing;878879/*kinput does not support XIMPreeditCallbacks and XIMStatusArea880at the same time, so use StatusCallback to draw the status881ourself882*/883for (i = 0; i < im_styles->count_styles; i++) {884if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) {885on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks);886break;887}888}889890for (i = 0; i < im_styles->count_styles; i++) {891if (im_styles->supported_styles[i] == on_the_spot_styles)892active_styles = im_styles->supported_styles[i];893if (im_styles->supported_styles[i] == ROOT_WINDOW_STYLES)894passive_styles = im_styles->supported_styles[i];895if (im_styles->supported_styles[i] == IN_PLACE_STYLES) {896in_place_styles = im_styles->supported_styles[i];897}898if (im_styles->supported_styles[i] == NO_STYLES) {899no_styles = im_styles->supported_styles[i];900}901}902903XFree(im_styles);904905if (active_styles != on_the_spot_styles) {906if (passive_styles == ROOT_WINDOW_STYLES)907active_styles = passive_styles;908else {909if (in_place_styles == IN_PLACE_STYLES){910active_styles = passive_styles = IN_PLACE_STYLES;911} else {912if (no_styles == NO_STYLES)913active_styles = passive_styles = NO_STYLES;914else915active_styles = passive_styles = 0;916}917}918} else {919if (!passiveStatusWindow) {920if (passive_styles != ROOT_WINDOW_STYLES) {921if (no_styles == NO_STYLES)922active_styles = passive_styles = NO_STYLES;923else924active_styles = passive_styles = 0;925}926} else927passive_styles = active_styles;928}929930if (active_styles == on_the_spot_styles) {931callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS);932if (callbacks == (XIMCallback *)NULL)933return False;934pX11IMData->callbacks = callbacks;935936for (i = 0; i < NCALLBACKS; i++, callbacks++) {937callbacks->client_data = (XPointer) pX11IMData->x11inputmethod;938callbacks->callback = callback_funcs[i];939}940941callbacks = pX11IMData->callbacks;942preedit = (XVaNestedList)XVaCreateNestedList(0,943XNPreeditStartCallback, &callbacks[PreeditStartIndex],944XNPreeditDoneCallback, &callbacks[PreeditDoneIndex],945XNPreeditDrawCallback, &callbacks[PreeditDrawIndex],946XNPreeditCaretCallback, &callbacks[PreeditCaretIndex],947NULL);948if (preedit == (XVaNestedList)NULL)949goto err;950/*always try XIMStatusCallbacks for active client...*/951{952if (on_the_spot_styles & XIMStatusCallbacks) {953status = (XVaNestedList)XVaCreateNestedList(0,954XNStatusStartCallback, &callbacks[StatusStartIndex],955XNStatusDoneCallback, &callbacks[StatusDoneIndex],956XNStatusDrawCallback, &callbacks[StatusDrawIndex],957NULL);958959if (status == NULL)960goto err;961}962pX11IMData->statusWindow = createStatusWindow(w);963pX11IMData->ic_active = XCreateIC(X11im,964XNClientWindow, w,965XNFocusWindow, w,966XNInputStyle, active_styles,967XNPreeditAttributes, preedit,968XNStatusAttributes, status,969NULL);970if (NULL != pX11IMData->statusWindow) {971pX11IMData->statusWindow->status_ready = True;972}973XFree((void *)status);974XFree((void *)preedit);975}976if (passiveStatusWindow) {977pX11IMData->ic_passive = pX11IMData->ic_active;978} else {979pX11IMData->ic_passive = XCreateIC(X11im,980XNClientWindow, w,981XNFocusWindow, w,982XNInputStyle, passive_styles,983NULL);984}985} else {986pX11IMData->ic_active = XCreateIC(X11im,987XNClientWindow, w,988XNFocusWindow, w,989XNInputStyle, active_styles,990NULL);991pX11IMData->ic_passive = pX11IMData->ic_active;992}993994// The code set the IC mode that the preedit state is not initialied995// at XmbResetIC. This attribute can be set at XCreateIC. I separately996// set the attribute to avoid the failure of XCreateIC at some platform997// which does not support the attribute.998if (pX11IMData->ic_active != 0)999XSetICValues(pX11IMData->ic_active,1000XNResetState, XIMPreserveState, NULL);1001if (pX11IMData->ic_passive != 0 &&1002pX11IMData->ic_active != pX11IMData->ic_passive)1003XSetICValues(pX11IMData->ic_passive,1004XNResetState, XIMInitialState, NULL);10051006pX11IMData->passiveStatusWindow = passiveStatusWindow;10071008if (pX11IMData->ic_active == (XIC)01009|| pX11IMData->ic_passive == (XIC)0) {1010return False;1011}10121013/* Unset focus to avoid unexpected IM on */1014setXICFocus(pX11IMData->ic_active, False);1015if (pX11IMData->ic_active != pX11IMData->ic_passive)1016setXICFocus(pX11IMData->ic_passive, False);10171018return True;10191020err:1021if (preedit)1022XFree((void *)preedit);1023THROW_OUT_OF_MEMORY_ERROR();1024return False;1025}10261027static int1028PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data)1029{1030JNIEnv *env = GetJNIEnv();1031X11InputMethodData *pX11IMData;10321033pX11IMData = getX11InputMethodData(env, (jobject)client_data);1034if (pX11IMData == NULL || pX11IMData->statusWindow == NULL) {1035return 0;1036}1037resetPassivePreeditText(pX11IMData->statusWindow);10381039return -1; /* unlimited length for preedit text */1040}10411042static void1043PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)1044{1045JNIEnv *env = GetJNIEnv();1046X11InputMethodData *pX11IMData;10471048pX11IMData = getX11InputMethodData(env, (jobject)client_data);1049if (pX11IMData == NULL) {1050return;1051}10521053if (!pX11IMData->isActiveClient) {1054resetPassivePreeditText(pX11IMData->statusWindow);1055shrink_status(pX11IMData->statusWindow);1056}1057else{1058JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,1059"clearComposedText",1060"(J)V",1061awt_util_nowMillisUTC());1062if ((*env)->ExceptionOccurred(env)) {1063(*env)->ExceptionDescribe(env);1064(*env)->ExceptionClear(env);1065}1066}1067}10681069/*1070* Translate the preedit draw callback items to Java values and invoke1071* X11InputMethod.dispatchComposedText().1072*1073* client_data: X11InputMethod object1074*/1075static void1076PreeditDrawCallback(XIC ic, XPointer client_data,1077XIMPreeditDrawCallbackStruct *pre_draw)1078{1079JNIEnv *env = GetJNIEnv();1080X11InputMethodData *pX11IMData = NULL;1081jmethodID x11imMethodID;10821083XIMText *text;1084jstring javastr = NULL;1085jintArray style = NULL;10861087/* printf("Native: PreeditDrawCallback() \n"); */1088if (pre_draw == NULL) {1089return;1090}1091AWT_LOCK();1092if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {1093goto finally;1094}10951096if (!pX11IMData->isActiveClient){1097if (ic == pX11IMData->ic_passive) {1098preedit_draw_passive(pX11IMData, pre_draw);1099}1100goto finally;1101}11021103if ((text = pre_draw->text) != NULL) {1104if (is_text_available(text)) {1105if (text->string.multi_byte != NULL) {1106if (pre_draw->text->encoding_is_wchar == False) {1107javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte);1108if (javastr == NULL) {1109goto finally;1110}1111} else {1112char *mbstr = wcstombsdmp(text->string.wide_char, text->length);1113if (mbstr == NULL) {1114goto finally;1115}1116javastr = JNU_NewStringPlatform(env, (const char *)mbstr);1117free(mbstr);1118if (javastr == NULL) {1119goto finally;1120}1121}1122}1123}1124if (text->feedback != NULL) {1125int cnt;1126jint *tmpstyle;11271128style = (*env)->NewIntArray(env, text->length);1129if (JNU_IsNull(env, style)) {1130(*env)->ExceptionClear(env);1131THROW_OUT_OF_MEMORY_ERROR();1132goto finally;1133}11341135if (sizeof(XIMFeedback) == sizeof(jint)) {1136/*1137* Optimization to avoid copying the array1138*/1139(*env)->SetIntArrayRegion(env, style, 0,1140text->length, (jint *)text->feedback);1141} else {1142tmpstyle = (jint *)malloc(sizeof(jint)*(text->length));1143if (tmpstyle == (jint *) NULL) {1144THROW_OUT_OF_MEMORY_ERROR();1145goto finally;1146}1147for (cnt = 0; cnt < (int)text->length; cnt++)1148tmpstyle[cnt] = text->feedback[cnt];1149(*env)->SetIntArrayRegion(env, style, 0,1150text->length, (jint *)tmpstyle);1151free(tmpstyle);1152}1153}1154}1155JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,1156"dispatchComposedText",1157"(Ljava/lang/String;[IIIIJ)V",1158javastr,1159style,1160(jint)pre_draw->chg_first,1161(jint)pre_draw->chg_length,1162(jint)pre_draw->caret,1163awt_util_nowMillisUTC());11641165if ((*env)->ExceptionOccurred(env)) {1166(*env)->ExceptionDescribe(env);1167(*env)->ExceptionClear(env);1168}11691170finally:1171AWT_UNLOCK();1172return;1173}11741175static void1176PreeditCaretCallback(XIC ic, XPointer client_data,1177XIMPreeditCaretCallbackStruct *pre_caret)1178{1179XIMPreeditDrawCallbackStruct pre_draw;11801181if (pre_caret != NULL && pre_caret->direction == XIMAbsolutePosition) {1182pre_draw.caret = pre_caret->position;1183pre_draw.chg_first = 0;1184pre_draw.chg_length = 0;1185pre_draw.text = NULL;1186PreeditDrawCallback(ic, client_data, &pre_draw);1187}1188}11891190static void1191StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data)1192{1193/*ARGSUSED*/1194/*printf("StatusStartCallback:\n"); */1195}11961197static void1198StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data)1199{1200/*ARGSUSED*/1201/*printf("StatusDoneCallback:\n"); */1202}12031204static void StatusDrawCallback1205(XIC ic, XPointer client_data, XIMStatusDrawCallbackStruct *status_draw)1206{1207/*ARGSUSED*/1208/*printf("StatusDrawCallback:\n"); */1209JNIEnv *env = GetJNIEnv();1210X11InputMethodData *pX11IMData = NULL;1211StatusWindow *statusWindow;1212int value_make = CWX|CWWidth|CWHeight;1213XRectangle logical, ink;1214XWindowChanges xwc;1215int len;12161217AWT_LOCK();12181219if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data))1220|| NULL == (statusWindow = pX11IMData->statusWindow)){1221goto finally;1222}12231224if (status_draw->type == XIMTextType) {1225XIMText *text = (status_draw->data).text;1226if (text != NULL) {1227if (text->string.multi_byte != NULL) {1228if(!strcmp(text->string.multi_byte," ")){1229wcscpy(statusWindow->status, L"");1230onoffStatusWindow(pX11IMData, 0, False);1231goto finally;1232}1233mbstowcs(statusWindow->status,1234(const char *)text->string.multi_byte,1235(size_t)MAX_STATUS_LEN);1236} else {1237if (0 == st_wcslen(text->string.wide_char)){1238wcscpy(statusWindow->status, L"");1239onoffStatusWindow(pX11IMData, 0, False);1240goto finally;1241}1242wcsncpy(statusWindow->status,1243text->string.wide_char,1244MAX_STATUS_LEN);1245}1246XwcTextExtents(statusWindow->fontset, statusWindow->status,1247st_wcslen(statusWindow->status), &ink, &logical);1248statusWindow->statusW = logical.width + BORDER_MARGIN;1249statusWindow->statusH = logical.height + BORDER_MARGIN;1250xwc.x = statusWindow->x - statusWindow->off_x;1251if (xwc.x < 0 ) xwc.x = 0;1252xwc.width = statusWindow->statusW;1253xwc.height = statusWindow->statusH;1254if (xwc.x + xwc.width > statusWindow->rootW){1255xwc.x = statusWindow->rootW - xwc.width;1256}1257XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);1258if (statusWindow->status_ready && statusWindow->on == True){1259onoffStatusWindow(pX11IMData, statusWindow->parent, True);1260}1261paintStatusWindow(statusWindow);1262if (statusWindow->peText)1263draw_preedit(statusWindow);1264}1265else {1266wcscpy(statusWindow->status, L"");1267/*just turnoff the status window1268paintStatusWindow(statusWindow);1269*/1270onoffStatusWindow(pX11IMData, 0, False);1271}1272}12731274finally:1275AWT_UNLOCK();1276}12771278/* return the string length without trailing spaces */1279/* work around code for Japanese AIXIM is implemented. */1280static int st_wcslen(wchar_t *string)1281{1282int len = (int32_t)wcslen(string);1283if (len == 0)1284return 0;1285for (len--;len >= 0; len--) {1286if (!iswspace((wint_t) string[len])) break;1287}1288return len+1;1289}12901291/*1292* Checks whether given XIMText contains a string data.1293*/1294static Bool is_text_available(XIMText * text)1295{1296if (text == NULL || text->length==0)1297return False;1298if (text->encoding_is_wchar) {1299if(text->string.wide_char[0] == L'\0')1300return False;1301} else {1302if (text->string.multi_byte[0] == '\0')1303return False;1304}1305return True;1306}13071308/*1309* check if preedit status is active1310*/1311static Bool isPreeditStateActive(XIC ic)1312{1313XIMPreeditState state = XIMPreeditUnKnown;1314XVaNestedList pr_atrb;1315char* nosupportAttr;13161317if (ic == NULL) return False;13181319pr_atrb = XVaCreateNestedList(0,XNPreeditState,&state,NULL);1320nosupportAttr=XGetICValues(ic,XNPreeditAttributes,pr_atrb,NULL);1321XFree(pr_atrb);1322if (nosupportAttr==NULL && state & XIMPreeditDisable)1323return False;1324else1325return True;1326}13271328static void * buf_insert(void * src, void * insert, int size,1329int src_len, int ins_len, int offset)1330{1331char *temp;13321333temp = realloc(src, size*(src_len+ins_len+1));1334if (temp == NULL) {1335THROW_OUT_OF_MEMORY_ERROR();1336return src;1337}1338if (offset != src_len) {1339memmove(&temp[size*(offset+ins_len)],1340&((char *)temp)[size*offset],1341size*(src_len-offset));1342}1343memcpy(&temp[size*offset], insert, size*ins_len);13441345return (void *)temp;1346}13471348static void * handle_buffer(void * source, void * insert,1349int size,int src_len, int ins_len,1350int del_len, int offset)1351{1352void * temp = source;13531354if (del_len > 0) {1355if (del_len == ins_len) {1356memcpy(&((char *)source)[size*offset], insert, size*ins_len);1357return source;1358}1359else if (src_len > offset+del_len) {1360memmove(&((char *)source)[size*offset],1361&((char *)source)[size*(offset+del_len)],1362size*(src_len-offset-del_len));1363}1364}1365if (ins_len > 0) {1366temp = buf_insert(source, insert, size, src_len,1367ins_len, offset);1368}1369return temp;1370}1371/*1372* Display the given preedit text to the root window which is ownd by1373* myself. All of the character is converted to wide char.1374* this function is used for the passive client.1375*/1376static void preedit_draw_passive(X11InputMethodData *pX11IMData,1377XIMPreeditDrawCallbackStruct *pre_draw)1378{1379XIMText *text;1380wchar_t *tempbuf = NULL;1381StatusWindow *statusWindow;1382wchar_t *cur_text;1383unsigned long *cur_attr;1384int cur_len = 0;1385int chg_len = pre_draw->chg_length;1386int chg_1st = pre_draw->chg_first;13871388if (NULL == (statusWindow = pX11IMData->statusWindow))1389return;1390cur_text = statusWindow->peText;1391cur_attr = statusWindow->peAttr;1392if (cur_text == NULL && pre_draw->text == NULL)1393return;13941395if (cur_text != NULL)1396cur_len = (int32_t)wcslen(cur_text);1397text = pre_draw->text;1398if (text == NULL) {1399/* delete only */1400if (cur_len > chg_1st+chg_len) {1401memmove(&cur_text[chg_1st],1402&cur_text[chg_1st+chg_len],1403sizeof(wchar_t)*(cur_len-chg_1st-chg_len));1404memmove(&cur_attr[chg_1st],1405&cur_attr[chg_1st+chg_len],1406sizeof(long)*(cur_len-chg_1st-chg_len));1407}1408if ((pre_draw->chg_length <= cur_len ) && (pre_draw->chg_length >0))1409cur_text[cur_len-pre_draw->chg_length] =L'\0';1410} else {1411/* insert or replace */1412int ins_len = 0;1413void * ins_text = NULL;14141415/* if invalid offset is specified, do nothing. */1416/* this fix is for aixim for eucTW */1417if (cur_len < chg_1st)1418return;1419if(is_text_available(text)) {1420/* insert or replace the text */1421if (text->encoding_is_wchar == False) {1422/* convert the text to wide chars.1423allocate enough size buffer1424*/1425tempbuf = (wchar_t *)malloc(sizeof(wchar_t)*(text->length+1));1426if (tempbuf == NULL) {1427THROW_OUT_OF_MEMORY_ERROR();1428return;1429}1430ins_len = (int32_t)mbstowcs(tempbuf, text->string.multi_byte,1431text->length);1432if (ins_len == -1) {1433free(tempbuf);1434return;1435}1436ins_text = (void *)tempbuf;1437}1438else {1439ins_len = text->length;1440ins_text = text->string.wide_char;1441}1442/* finish prepare the data to be inserted */14431444statusWindow->peText =1445handle_buffer(cur_text, ins_text, sizeof(wchar_t),1446cur_len, ins_len, chg_len, chg_1st);1447statusWindow->peAttr =1448handle_buffer(cur_attr, text->feedback, sizeof(long),1449cur_len, ins_len, chg_len, chg_1st);1450statusWindow->peText[cur_len-chg_len+ins_len] =L'\0';14511452if (tempbuf != NULL)1453free(tempbuf);1454} /* endof insert or replace text */1455else {1456/* change attribute only */1457memcpy(&cur_attr[chg_1st], text->feedback,1458sizeof(long)*text->length);1459}1460}1461statusWindow->peCaret= pre_draw->caret;1462draw_preedit(statusWindow);1463if (statusWindow->on && wcslen(statusWindow->peText) > 0)1464onoffStatusWindow(pX11IMData, statusWindow->parent, True);1465else if (wcslen(statusWindow->status) == 0)1466onoffStatusWindow(pX11IMData, 0, False);1467}14681469/*1470* reset predit test of passive mode1471*/1472static void1473resetPassivePreeditText(StatusWindow *statusWindow)1474{1475if (NULL == statusWindow) return;1476if(statusWindow->peText != NULL) {1477free(statusWindow->peText);1478statusWindow->peText = NULL;1479}1480if(statusWindow->peAttr != NULL) {1481free(statusWindow->peAttr);1482statusWindow->peAttr = NULL;1483}1484statusWindow->peCaret= 0;1485}14861487static void draw_caret(StatusWindow *statusWindow, GC gc, int pos)1488{1489if (NULL == statusWindow) return;1490XSetFunction(dpy, gc, GXinvert);1491XDrawLine(dpy, statusWindow->w,1492gc, pos, STATUS_BORDER/2,1493pos, STATUS_BORDER/2+statusWindow->fOff);1494XSetFunction(dpy, gc, GXcopy);1495}14961497static int get_next_attr(int len, unsigned long *attr)1498{1499int count;15001501for (count = 1; count < len; count++) {1502if ((attr[count-1] & PREEDIT_ATTR_MASK)1503!= (attr[count] & PREEDIT_ATTR_MASK))1504break;1505}1506return count;1507}15081509static void draw_preedit(StatusWindow *statusWindow)1510{1511unsigned long *attr;1512int x_pos,x_caret;1513unsigned int len;1514int len_disp, pos;1515wchar_t *str;1516GC gc;1517XRectangle ink, rect, rect_c;1518Bool caret_done = False;15191520if (NULL == statusWindow) return;1521align_status(statusWindow);1522XFillRectangle(dpy, statusWindow->w,1523statusWindow->bgGC,1524statusWindow->statusW,0,1525statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN,1526statusWindow->fBot+2);152715281529XDrawLine(dpy, statusWindow->w, statusWindow->fgGC,1530statusWindow->statusW, 0,1531statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 0);1532XDrawLine(dpy, statusWindow->w, statusWindow->fgGC,1533statusWindow->statusW, statusWindow->fBot+2,1534statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN,1535statusWindow->fBot+2);1536XDrawLine(dpy, statusWindow->w, statusWindow->fgGC,1537statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 0,1538statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN,1539statusWindow->fBot+2);1540if (0 == statusWindow->statusW)1541XDrawLine(dpy, statusWindow->w, statusWindow->fgGC,15420, 0, 0, statusWindow->fBot+2);15431544str = statusWindow->peText;15451546if (str != NULL && (len = (int32_t)wcslen(str)) != 0) {1547pos = 0;1548attr = statusWindow->peAttr;1549x_pos = x_caret = statusWindow->statusW + STATUS_BORDER;1550while((int)len-1 >= pos) {1551len_disp = get_next_attr(len - pos, &attr[pos]);1552if (attr[pos] & XIMReverse) {1553gc = statusWindow->bgGC;1554}1555else {1556gc = statusWindow->fgGC;1557}1558XwcTextExtents(statusWindow->fontset,1559&str[pos],1560len_disp, &ink, &rect);1561XwcDrawImageString(dpy, statusWindow->w,1562statusWindow->fontset, gc,1563x_pos, statusWindow->fOff+1, &str[pos], len_disp);1564if (attr[pos] & XIMUnderline) {1565XDrawLine(dpy, statusWindow->w,1566gc, x_pos, statusWindow->fBot,1567x_pos+rect.width, statusWindow->fBot);1568}1569if (!caret_done) {1570if( statusWindow->peCaret >= pos &&1571statusWindow->peCaret <= pos+len_disp) {1572if (statusWindow->peCaret == 0)1573x_caret = x_pos;1574else if (statusWindow->peCaret == pos+len_disp)1575x_caret = x_pos+rect.width;1576else {1577XwcTextExtents(statusWindow->fontset,1578&str[pos],1579statusWindow->peCaret-pos,1580&ink, &rect_c);1581x_caret = x_pos+ rect_c.width;1582}1583x_caret-=CARET_OFFSET;1584caret_done = True;1585}1586}1587pos += len_disp;1588x_pos += rect.width;1589}1590if (caret_done)1591draw_caret(statusWindow, statusWindow->fgGC, x_caret);1592}1593}15941595/* calc required status window size and resize the window */1596static void align_status(StatusWindow *statusWindow)1597{1598int len_st, len_pe = 0;1599XRectangle rect_st, rect_pe, ink;1600Dimension cur_w;1601int value_make = CWX|CWWidth|CWHeight;1602XWindowChanges xwc;16031604if (NULL == statusWindow) return;1605if ((len_st = st_wcslen(statusWindow->status)) == 01606&& (statusWindow->peText == NULL || st_wcslen(statusWindow->peText) == 0 ))1607return;16081609rect_pe.x = rect_pe.y = rect_pe.width = rect_pe.height = 0;16101611XwcTextExtents(statusWindow->fontset,1612statusWindow->status,1613len_st, &ink, &rect_st);1614if (statusWindow->peText != NULL1615&& (len_pe = (int32_t)wcslen(statusWindow->peText)) > 0) {1616XwcTextExtents(statusWindow->fontset,1617statusWindow->peText,1618len_pe, &ink, &rect_pe);1619}1620statusWindow->fOff = max(-rect_st.y, -rect_pe.y);1621statusWindow->fBot = max(rect_st.height, rect_pe.height);1622statusWindow->statusW =rect_st.width;1623if (rect_st.width > 0) statusWindow->statusW += BORDER_MARGIN;1624statusWindow->peTextW = rect_pe.width;16251626xwc.x = statusWindow->x - statusWindow->off_x;1627if (xwc.x < 0 ) xwc.x = 0;16281629if (len_pe > 0) {1630xwc.width = statusWindow->statusW1631+ statusWindow->peTextW + BORDER_MARGIN + 1;1632xwc.height = statusWindow->fBot + BORDER_MARGIN;1633} else {1634xwc.width = statusWindow->statusW;1635xwc.height = statusWindow->fBot + BORDER_MARGIN;1636}1637if (xwc.x + xwc.width > statusWindow->rootW){1638xwc.x = statusWindow->rootW - xwc.width;1639}1640XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);1641}16421643static void shrink_status(StatusWindow *statusWindow)1644{1645int value_make = CWX|CWWidth|CWHeight;1646XWindowChanges xwc;16471648if (NULL == statusWindow) return;1649xwc.width = statusWindow->statusW;1650xwc.height = statusWindow->statusH;1651statusWindow->peTextW = 0;1652xwc.x = statusWindow->x - statusWindow->off_x;1653if (xwc.x < 0 ) xwc.x = 0;1654if (xwc.x + xwc.width > statusWindow->rootW){1655xwc.x = statusWindow->rootW - xwc.width;1656}1657XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);1658}16591660static Bool isNativeIm()1661{1662#define XIMMODIFIER "@im="1663#define XIM_SERVER_CATEGORY "@server="1664char *immodifiers;1665char *imserver, *imserverPtr;1666Atom imserverAtom;16671668if (!(immodifiers = getenv("XMODIFIERS"))) return True;1669if (!(imserver = calloc(1,strlen(immodifiers)+strlen(XIM_SERVER_CATEGORY)+1))) return True;1670if (!(immodifiers = strstr(immodifiers,XIMMODIFIER))) return True;1671immodifiers += strlen(XIMMODIFIER);1672strcpy(imserver,XIM_SERVER_CATEGORY);1673imserverPtr = imserver + strlen(imserver);1674while(*immodifiers != '@' && *immodifiers != '\0') {1675*imserverPtr = *immodifiers;1676imserverPtr++;1677immodifiers++;1678}1679imserverAtom = XInternAtom(awt_display, imserver, True);1680free(imserver);1681if (imserverAtom > 0)1682return False;1683else1684return True;1685}16861687static Window getGrandParent(Window parent)1688{1689Window containerWindow,rootWindow,tmp;1690Window *ignoreWindowPtr;1691unsigned int ignoreUnit;1692Window grandParent=0;1693XWindowAttributes xwa;1694Atom WM_STATE;1695Atom type = None;1696int32_t format;1697unsigned long nitems, after;1698unsigned char * data;16991700if (parent == 0) return grandParent;1701WM_STATE = XInternAtom(dpy, "WM_STATE", True);1702if (WM_STATE == None) return grandParent;17031704tmp=parent;1705while(XQueryTree(dpy, tmp,1706&rootWindow, &containerWindow,1707&ignoreWindowPtr, &ignoreUnit)){1708XFree(ignoreWindowPtr);1709if (containerWindow == rootWindow) break;1710if (XGetWindowProperty(dpy, containerWindow, WM_STATE,17110, 0, False, AnyPropertyType,1712&type, &format, &nitems, &after, &data) == Success) {1713XFree(data);1714if (type) {1715XGetWindowAttributes(dpy, containerWindow, &xwa);1716if (FALSE == xwa.override_redirect){1717grandParent=containerWindow;1718}1719}1720}1721tmp=containerWindow;1722}1723return grandParent;1724}17251726static void moveStatusWindow(StatusWindow *statusWindow)1727{1728XWindowAttributes xwa;1729Window child;1730int x, y, width;1731Window target;17321733if (NULL == statusWindow) return;1734if (statusWindow->grandParent) {1735target = statusWindow->grandParent;1736} else {1737target = statusWindow->parent;1738}1739XGetWindowAttributes(dpy, target, &xwa);1740XTranslateCoordinates(dpy,1741target, xwa.root,17420, 0,1743&x, &y,1744&child);1745if (statusWindow->x != x1746|| statusWindow->y != y1747|| statusWindow->width != xwa.width1748|| statusWindow->height != xwa.height){1749statusWindow->x = x;1750statusWindow->y = y;1751statusWindow->height = xwa.height;1752statusWindow->width = xwa.width;1753x = statusWindow->x - statusWindow->off_x;1754y = statusWindow->y + statusWindow->height + statusWindow->off_y;1755if (x < 0 ){1756x = 0;1757}1758if (statusWindow->peTextW > 0) {1759width = statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN + 1;1760if (x + width > statusWindow->rootW){1761x = statusWindow->rootW - width;1762}1763} else {1764if (x + statusWindow->statusW > statusWindow->rootW){1765x = statusWindow->rootW - statusWindow->statusW;1766}1767}1768if (y + statusWindow->statusH > statusWindow->rootH){1769y = statusWindow->rootH - statusWindow->statusH;1770}1771XMoveWindow(dpy, statusWindow->w, x, y);1772}1773}17741775static void arrange_window_stack(StatusWindow* statusWindow)1776{1777XWindowChanges xwc;1778int value_make = CWSibling|CWStackMode;1779Window root, parent, *children;1780unsigned int nchildren;17811782if (NULL == statusWindow) return;1783if (XQueryTree(dpy, statusWindow->parent,1784&root, &parent, &children, &nchildren)){1785XFree(children);1786xwc.sibling = parent;1787while(XQueryTree(dpy, xwc.sibling, &root, &parent, &children, &nchildren)) {1788XFree(children);1789if (root != parent) {1790xwc.sibling = parent;1791} else {1792break;1793}1794}1795xwc.stack_mode = Above;1796XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);1797}1798}17991800static int count_missing_fonts(char **charset_list, int charset_count)1801{1802int i,j;1803if (charset_count > 0) {1804j=charset_count;1805for(i=0; i < charset_count; i++) {1806if ((strstr(charset_list[i], "IBM-udc")) ||1807(strstr(charset_list[i], "IBM-sbd")) ||1808(strstr(charset_list[i], "IBM-ucdTW")))1809j--;1810}1811return j;1812}1813else1814return 0;1815}18161817static XFontSet create_fontset_name(char * font_name, Bool force)1818{1819XFontSet fontset = NULL;1820char **charset_list;1821int charset_count;1822char *def_string;1823int missing_fonts;18241825fontset = XCreateFontSet(dpy, font_name,1826&charset_list, &charset_count, &def_string);1827if (charset_count > 0) {1828missing_fonts = count_missing_fonts(charset_list,1829charset_count);1830XFreeStringList(charset_list);1831if (fontset && (missing_fonts > 0)) {1832if (!force) {1833XFreeFontSet(dpy, fontset);1834fontset = NULL;1835}1836}1837}1838return fontset;1839}18401841static XFontSet create_fontset()1842{1843XFontSet fontset = NULL;1844int i;1845static char * fontlist[] = {1846"-dt-interface user-medium-r-normal-S*-*-*-*-*-*-*-*-*",1847"-*-*-medium-r-normal-*-14-*-*-*-c-*-*-*",1848"-*-*-medium-r-normal-*-14-*-*-*-m-*-*-*",1849"-*-*-medium-r-normal--14-0-0-0-m-*-*-*",1850"-monotype-sansmonowt-medium-r-normal--14-*-*-*-m-*-*-*",1851"-*--14-*",1852"-dt-interface user-medium-r-normal-s*-*-*-*-*-*-*-*-*",1853"-*--16-*",1854"-*--17-*",1855"-*--18-*",1856"-*--19-*",1857"-*--20-*",1858"-*--24-*",1859NULL};18601861for (i=0; fontlist[i] != NULL && fontset==NULL; i++)1862fontset = create_fontset_name(fontlist[i], False);18631864if (!fontset)1865fprintf(stdout, "Cannot load fonts for IMF.\n");1866return fontset;1867}18681869static Window get_current_focus(XIC ic) {1870Window w = 0;1871if (ic != NULL)1872XGetICValues(ic, XNFocusWindow, &w, NULL);1873return w;1874}18751876JNIEXPORT jboolean JNICALL1877Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env,1878jobject this,1879jlong display)1880{1881Bool registered;18821883AWT_LOCK();18841885dpy = (Display *)jlong_to_ptr(display);18861887if (X11im == NULL) {1888X11im = XOpenIM(dpy, NULL, NULL, NULL);1889}18901891AWT_UNLOCK();18921893return JNI_TRUE;1894}18951896JNIEXPORT jboolean JNICALL1897Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env,1898jobject this,1899jlong window)1900{1901X11InputMethodData *pX11IMData;1902jobject globalRef;1903XIC ic;19041905AWT_LOCK();19061907if (!window) {1908JNU_ThrowNullPointerException(env, "NullPointerException");1909AWT_UNLOCK();1910return JNI_FALSE;1911}19121913pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData));1914if (pX11IMData == NULL) {1915THROW_OUT_OF_MEMORY_ERROR();1916AWT_UNLOCK();1917return JNI_FALSE;1918}19191920globalRef = (*env)->NewGlobalRef(env, this);1921pX11IMData->x11inputmethod = globalRef;1922pX11IMData->statusWindow = NULL;19231924setX11InputMethodData(env, this, pX11IMData);19251926if (createXIC(env, pX11IMData, (Window)window) == False) {1927destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData);1928pX11IMData = (X11InputMethodData *) NULL;1929setX11InputMethodData(env, this, pX11IMData);1930if ((*env)->ExceptionCheck(env)) {1931goto finally;1932}1933}19341935finally:1936AWT_UNLOCK();1937return (pX11IMData != NULL);1938}19391940JNIEXPORT void JNICALL1941Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env,1942jobject this,1943jlong w,1944jboolean req,1945jboolean active)1946{1947X11InputMethodData *pX11IMData;1948AWT_LOCK();1949pX11IMData = getX11InputMethodData(env, this);1950if (pX11IMData == NULL) {1951AWT_UNLOCK();1952return;1953}19541955if (req) {1956if (!w) {1957AWT_UNLOCK();1958return;1959}1960pX11IMData->isActiveClient = active;1961pX11IMData->current_ic = active ?1962pX11IMData->ic_active : pX11IMData->ic_passive;1963/*1964* On Solaris2.6, setXICWindowFocus() has to be invoked1965* before setting focus.1966*/1967get_current_focus(pX11IMData->current_ic); /* workaround for kinput2 and SCIM */1968if (currentFocusWindow != w) {1969setXICWindowFocus(pX11IMData->current_ic, w);1970setXICFocus(pX11IMData->current_ic, req);1971currentX11InputMethodInstance = pX11IMData->x11inputmethod;1972currentFocusWindow = w;1973} else {1974setXICFocus(pX11IMData->current_ic, req);1975}1976if ((active || pX11IMData->passiveStatusWindow)1977&& (pX11IMData->statusWindow && pX11IMData->statusWindow->on))1978onoffStatusWindow(pX11IMData, w, True);1979} else {1980currentX11InputMethodInstance = NULL;1981currentFocusWindow = 0;1982onoffStatusWindow(pX11IMData, 0, False);1983if (pX11IMData->current_ic != NULL)1984setXICFocus(pX11IMData->current_ic, req);19851986pX11IMData->current_ic = (XIC)0;1987}19881989XFlush(dpy);1990AWT_UNLOCK();1991}19921993/*1994* Class: sun_awt_X11InputMethodBase1995* Method: initIDs1996* Signature: ()V1997* This function gets called from the static initializer for1998* X11InputMethod.java to initialize the fieldIDs for fields1999* that may be accessed from C2000*/2001JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_initIDs2002(JNIEnv *env, jclass cls)2003{2004x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J");2005}20062007/*2008* Class: sun_awt_X11InputMethodBase2009* Method: turnoffStatusWindow2010* Signature: ()V2011*/2012JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_turnoffStatusWindow2013(JNIEnv *env, jobject this)2014{2015X11InputMethodData *pX11IMData;2016StatusWindow *statusWindow;20172018AWT_LOCK();20192020if (NULL == currentX11InputMethodInstance2021|| NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))2022|| NULL == (statusWindow = pX11IMData->statusWindow)2023|| !statusWindow->on ){2024AWT_UNLOCK();2025return;2026}2027onoffStatusWindow(pX11IMData, 0, False);2028statusWindow->on = False;20292030AWT_UNLOCK();2031}20322033/*2034* Class: sun_awt_X11InputMethodBase2035* Method: disposeXIC2036* Signature: ()V2037*/2038JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_disposeXIC2039(JNIEnv *env, jobject this)2040{2041X11InputMethodData *pX11IMData = NULL;20422043AWT_LOCK();2044pX11IMData = getX11InputMethodData(env, this);2045if (pX11IMData == NULL) {2046AWT_UNLOCK();2047return;2048}20492050setX11InputMethodData(env, this, NULL);20512052if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) {2053currentX11InputMethodInstance = NULL;2054currentFocusWindow = 0;2055}2056destroyX11InputMethodData(env, pX11IMData);2057AWT_UNLOCK();2058}20592060/*2061* Class: sun_awt_X11InputMethodBase2062* Method: resetXIC2063* Signature: ()Ljava/lang/String;2064*/2065JNIEXPORT jstring JNICALL Java_sun_awt_X11InputMethodBase_resetXIC2066(JNIEnv *env, jobject this)2067{2068X11InputMethodData *pX11IMData;2069char *xText = NULL;2070jstring jText = (jstring)0;20712072AWT_LOCK();2073pX11IMData = getX11InputMethodData(env, this);2074if (pX11IMData == NULL) {2075AWT_UNLOCK();2076return jText;2077}20782079if (pX11IMData->current_ic) {2080if (!isPreeditStateActive(pX11IMData->current_ic)) {2081xText = NULL;2082} else {2083if (!(pX11IMData->forceReset))2084setXICFocus(pX11IMData->current_ic, FALSE);2085xText = XmbResetIC(pX11IMData->current_ic);2086if (!(pX11IMData->forceReset))2087setXICFocus(pX11IMData->current_ic, TRUE);2088}2089} else {2090/*2091* If there is no reference to the current XIC, try to reset both XICs.2092*/2093if (!isPreeditStateActive(pX11IMData->ic_active))2094xText = NULL;2095else2096xText = XmbResetIC(pX11IMData->ic_active);2097/*it may also means that the real client component does2098not have focus -- has been deactivated... its xic should2099not have the focus, bug#4284651 showes reset XIC for htt2100may bring the focus back, so de-focus it again.2101*/2102setXICFocus(pX11IMData->ic_active, FALSE);2103if (pX11IMData->ic_active != pX11IMData->ic_passive) {2104char *tmpText;2105if (!isPreeditStateActive(pX11IMData->ic_passive))2106tmpText = NULL;2107else2108tmpText = XmbResetIC(pX11IMData->ic_passive);2109setXICFocus(pX11IMData->ic_passive, FALSE);2110if (xText == (char *)NULL && tmpText)2111xText = tmpText;2112}2113}2114if (xText != NULL) {2115jText = JNU_NewStringPlatform(env, (const char *)xText);2116XFree((void *)xText);2117}21182119/* workaround2120* Some IME do not call PreeditDoneCallback routine even2121* when XmbResetIC is called. I force to reset the preedit string.2122*/2123if (!pX11IMData->isActiveClient) {2124resetPassivePreeditText(pX11IMData->statusWindow);2125shrink_status(pX11IMData->statusWindow);2126} else {2127JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,2128"clearComposedText",2129"()V");2130if ((*env)->ExceptionOccurred(env)) {2131(*env)->ExceptionDescribe(env);2132(*env)->ExceptionClear(env);2133}2134}21352136AWT_UNLOCK();2137return jText;2138}21392140/*2141* Class: sun_awt_X11InputMethodBase2142* Method: setCompositionEnabledNative2143* Signature: (Z)Z2144*2145* This method tries to set the XNPreeditState attribute associated with the current2146* XIC to the passed in 'enable' state.2147*2148* Return JNI_TRUE if XNPreeditState attribute is successfully changed to the2149* 'enable' state; Otherwise, if XSetICValues fails to set this attribute,2150* java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this2151* method fails due to other reasons.2152*/2153JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethodBase_setCompositionEnabledNative2154(JNIEnv *env, jobject this, jboolean enable)2155{2156X11InputMethodData *pX11IMData;2157char * ret = NULL;2158XVaNestedList pr_atrb;21592160AWT_LOCK();2161pX11IMData = getX11InputMethodData(env, this);21622163if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {2164AWT_UNLOCK();2165return JNI_FALSE;2166}21672168pr_atrb = XVaCreateNestedList(0, XNPreeditState,2169(enable ? XIMPreeditEnable : XIMPreeditDisable), NULL);2170ret = XSetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL);2171XFree((void *)pr_atrb);2172AWT_UNLOCK();21732174if ((ret != 0) &&2175((strcmp(ret, XNPreeditAttributes) == 0)2176|| (strcmp(ret, XNPreeditState) == 0))) {2177JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");2178}21792180return (jboolean)(ret == 0);2181}21822183/*2184* Class: sun_awt_X11InputMethodBase2185* Method: isCompositionEnabledNative2186* Signature: ()Z2187*2188* This method tries to get the XNPreeditState attribute associated with the current XIC.2189*2190* Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if2191* XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException2192* will be thrown. JNI_FALSE is returned if this method fails due to other reasons.2193*/2194JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethodBase_isCompositionEnabledNative2195(JNIEnv *env, jobject this)2196{2197X11InputMethodData *pX11IMData = NULL;2198char * ret = NULL;2199XIMPreeditState state = XIMPreeditUnKnown;2200XVaNestedList pr_atrb;22012202AWT_LOCK();2203pX11IMData = getX11InputMethodData(env, this);22042205if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {2206AWT_UNLOCK();2207return JNI_FALSE;2208}22092210pr_atrb = XVaCreateNestedList(0, XNPreeditState, &state, NULL);2211ret = XGetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL);2212XFree((void *)pr_atrb);2213AWT_UNLOCK();22142215if ((ret != 0) &&2216((strcmp(ret, XNPreeditAttributes) == 0)2217|| (strcmp(ret, XNPreeditState) == 0))) {2218JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");2219return JNI_FALSE;2220}22212222return (jboolean)(state == XIMPreeditEnable);2223}22242225JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow2226(JNIEnv *env, jobject this, jlong window)2227{22282229}22302231/*2232* Class: sun_awt_X11InputMethod2233* Method: setStatusAreaVisible2234* Signature: (ZJ)V2235*/2236JNIEXPORT void JNICALL Java_sun_awt_X11InputMethod_setStatusAreaVisible2237(JNIEnv *env, jobject this, jboolean value, jlong data)2238{2239X11InputMethodData *pX11IMData;22402241pX11IMData = getX11InputMethodData(env, this);2242if (NULL == pX11IMData) return;2243if (NULL == pX11IMData->statusWindow) return;22442245if ((int)value){2246pX11IMData->statusWindow->on = True;2247}else{2248pX11IMData->statusWindow->on = False;2249}2250return;2251}225222532254