/* * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #ifdef HEADLESS #error This file should not be included in headless library #endif #include #include #include #include #include #if defined(AIX) #include #include #include #include #endif #include "awt.h" #include "awt_p.h" #include #include #define THROW_OUT_OF_MEMORY_ERROR() \ JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL) #if !defined(AIX) #define RESUME_ENABLE 1 #endif struct X11InputMethodIDs { jfieldID pData; } x11InputMethodIDs; #if !defined(AIX) static void PreeditStartCallback(XIC, XPointer, XPointer); #else static int PreeditStartCallback(XIC, XPointer, XPointer); #endif static void PreeditDoneCallback(XIC, XPointer, XPointer); static void PreeditDrawCallback(XIC, XPointer, XIMPreeditDrawCallbackStruct *); static void PreeditCaretCallback(XIC, XPointer, XIMPreeditCaretCallbackStruct *); #if defined(__linux__) || defined(MACOSX) || defined(AIX) static void StatusStartCallback(XIC, XPointer, XPointer); static void StatusDoneCallback(XIC, XPointer, XPointer); static void StatusDrawCallback(XIC, XPointer, XIMStatusDrawCallbackStruct *); #endif #define ROOT_WINDOW_STYLES (XIMPreeditNothing | XIMStatusNothing) #define NO_STYLES (XIMPreeditNone | XIMStatusNone) #if defined(AIX) /* added style to allow for in-place composition, such as "dead" keys for accents */ #define IN_PLACE_STYLES (XIMPreeditNothing | XIMStatusNone) #endif #define PreeditStartIndex 0 #define PreeditDoneIndex 1 #define PreeditDrawIndex 2 #define PreeditCaretIndex 3 #if defined(__linux__) || defined(MACOSX) || defined(AIX) #define StatusStartIndex 4 #define StatusDoneIndex 5 #define StatusDrawIndex 6 #define NCALLBACKS 7 #else #define NCALLBACKS 4 #endif #if defined(AIX) #define STATUS_BORDER 2 /* Status Border width */ #define CARET_OFFSET 1 /* Offset of caret position (pixel) */ #define BORDER_MARGIN 3 /* BORDER MARGIN width */ #define STATUS_MARGIN 7 /* Margin between the status window and its parent window */ #define PREEDIT_ATTR_MASK (XIMReverse|XIMUnderline) /* Preedit attribute which host adapter can handle */ #endif /* * Callback function pointers: the order has to match the *Index * values above. */ static XIMProc callback_funcs[NCALLBACKS] = { (XIMProc)PreeditStartCallback, (XIMProc)PreeditDoneCallback, (XIMProc)PreeditDrawCallback, (XIMProc)PreeditCaretCallback, #if defined(__linux__) || defined(MACOSX) || defined(AIX) (XIMProc)StatusStartCallback, (XIMProc)StatusDoneCallback, (XIMProc)StatusDrawCallback, #endif }; #if defined(__linux__) || defined(MACOSX) || defined(AIX) #define MAX_STATUS_LEN 100 typedef struct { Window w; /*status window id */ Window root; /*the root window id */ Window parent; /*parent shell window */ #if defined(AIX) Window grandParent; /*window has WM frame */ #endif int x, y; /*parent's upperleft position */ int width, height; /*parent's width, height */ GC lightGC; /*gc for light border */ GC dimGC; /*gc for dim border */ GC bgGC; /*normal painting */ GC fgGC; /*normal painting */ int statusW, statusH; /*status window's w, h */ int rootW, rootH; /*root window's w, h */ int bWidth; /*border width */ #if !defined(AIX) char status[MAX_STATUS_LEN]; /*status text */ #else wchar_t status[MAX_STATUS_LEN+1]; /*status text */ #endif XFontSet fontset; /*fontset for drawing */ int off_x, off_y; Bool on; /*if the status window on*/ #if defined(AIX) int fOff; /* font base line(in pixel) from top */ int fBot; /* font bottom line(in pixel) from top */ int peTextW; /* Composition text width in pixel */ wchar_t* peText; /* Composed string (wide char.) */ XIMFeedback* peAttr; /* Composed text attribute */ int peCaret; /* Caret position in number of character */ Bool status_ready; /* Not draw Status at XCreateIC */ #endif } StatusWindow; #endif /* * X11InputMethodData keeps per X11InputMethod instance information. A pointer * to this data structure is kept in an X11InputMethod object (pData). */ typedef struct _X11InputMethodData { XIC current_ic; /* current X Input Context */ XIC ic_active; /* X Input Context for active clients */ XIC ic_passive; /* X Input Context for passive clients */ XIMCallback *callbacks; /* callback parameters */ jobject x11inputmethod; /* global ref to X11InputMethod instance */ /* associated with the XIC */ #if defined(__linux__) || defined(MACOSX) || defined(AIX) StatusWindow *statusWindow; /* our own status window */ #endif #if !defined(AIX) char *lookup_buf; /* buffer used for XmbLookupString */ int lookup_buf_len; /* lookup buffer size in bytes */ #else Bool passiveStatusWindow;/* Passive Client uses StatusWindow */ Bool isActiveClient; /* True:clinet is active */ Bool forceReset; /* True: call resetXIC before UnsetICFocus */ #endif } X11InputMethodData; #if defined(RESUME_ENABLE) /* * When XIC is created, a global reference is created for * sun.awt.X11InputMethod object so that it could be used by the XIM callback * functions. This could be a dangerous thing to do when the original * X11InputMethod object is garbage collected and as a result, * destroyX11InputMethodData is called to delete the global reference. * If any XIM callback function still holds and uses the "already deleted" * global reference, disaster is going to happen. So we have to maintain * a list for these global references which is consulted first when the * callback functions or any function tries to use "currentX11InputMethodObject" * which always refers to the global reference try to use it. * */ typedef struct _X11InputMethodGRefNode { jobject inputMethodGRef; struct _X11InputMethodGRefNode* next; } X11InputMethodGRefNode; X11InputMethodGRefNode *x11InputMethodGRefListHead = NULL; #endif /* reference to the current X11InputMethod instance, it is always point to the global reference to the X11InputMethodObject since it could be referenced by different threads. */ jobject currentX11InputMethodInstance = NULL; Window currentFocusWindow = 0; /* current window that has focus for input method. (the best place to put this information should be currentX11InputMethodInstance's pData) */ static XIM X11im = NULL; Display * dpy = NULL; #define GetJNIEnv() (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2) #if defined(RESUME_ENABLE) static void DestroyXIMCallback(XIM, XPointer, XPointer); static void OpenXIMCallback(Display *, XPointer, XPointer); #endif #if !defined(AIX) /* Solaris XIM Extention */ #define XNCommitStringCallback "commitStringCallback" static void CommitStringCallback(XIC, XPointer, XPointer); #endif static X11InputMethodData * getX11InputMethodData(JNIEnv *, jobject); static void setX11InputMethodData(JNIEnv *, jobject, X11InputMethodData *); static void destroyX11InputMethodData(JNIEnv *, X11InputMethodData *); static void freeX11InputMethodData(JNIEnv *, X11InputMethodData *); #if defined(__solaris__) || defined(AIX) /* Prototype for this function is missing in Solaris X11R6 Xlib.h */ extern char *XSetIMValues( #if NeedVarargsPrototypes XIM /* im */, ... #endif ); #endif #if defined(AIX) static int st_wcslen(wchar_t *string); static Bool isPreeditStateActive(XIC ic); static void * buf_insert(void * src, void * insert, int size, int src_len, int ins_len, int offset); static void * handle_buffer(void * source, void * insert, int size, int src_len, int ins_len, int del_len, int offset); static void preedit_draw_passive(X11InputMethodData *pX11IMData, XIMPreeditDrawCallbackStruct *pre_draw); static void resetPassivePreeditText(StatusWindow *statusWindow); static void draw_caret(StatusWindow *statusWindow, GC gc, int pos); static int get_next_attr(int len, unsigned long *attr); static void draw_preedit(StatusWindow *statusWindow); static void align_status(StatusWindow *statusWindow); static void shrink_status(StatusWindow *statusWindow); static GC create_gc(Window win, Bool isReverse); static XFontSet create_fontset(void); static Bool is_text_available(XIMText * text); static Bool isNativeIm(); static Window getGrandParent(Window parent); static void moveStatusWindow(StatusWindow *statusWindow); static void arrange_window_stack(StatusWindow* statusWindow); static Window get_current_focus(XIC ic); #endif /* * This function is stolen from /src/solaris/hpi/src/system_md.c * It is used in setting the time in Java-level InputEvents */ jlong awt_util_nowMillisUTC() { struct timeval t; gettimeofday(&t, NULL); return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000); } /* * Converts the wchar_t string to a multi-byte string calling wcstombs(). A * buffer is allocated by malloc() to store the multi-byte string. NULL is * returned if the given wchar_t string pointer is NULL or buffer allocation is * failed. */ static char * wcstombsdmp(wchar_t *wcs, int len) { size_t n; char *mbs; if (wcs == NULL) return NULL; n = len*MB_CUR_MAX + 1; mbs = (char *) malloc(n * sizeof(char)); if (mbs == NULL) { THROW_OUT_OF_MEMORY_ERROR(); return NULL; } /* TODO: check return values... Handle invalid characters properly... */ if (wcstombs(mbs, wcs, n) == (size_t)-1) { free(mbs); return NULL; } return mbs; } #if defined(RESUME_ENABLE) /* * Returns True if the global reference is still in the list, * otherwise False. */ static Bool isX11InputMethodGRefInList(jobject imGRef) { X11InputMethodGRefNode *pX11InputMethodGRef = x11InputMethodGRefListHead; if (imGRef == NULL) { return False; } while (pX11InputMethodGRef != NULL) { if (pX11InputMethodGRef->inputMethodGRef == imGRef) { return True; } pX11InputMethodGRef = pX11InputMethodGRef->next; } return False; } /* * Add the new created global reference to the list. */ static void addToX11InputMethodGRefList(jobject newX11InputMethodGRef) { X11InputMethodGRefNode *newNode = NULL; if (newX11InputMethodGRef == NULL || isX11InputMethodGRefInList(newX11InputMethodGRef)) { return; } newNode = (X11InputMethodGRefNode *)malloc(sizeof(X11InputMethodGRefNode)); if (newNode == NULL) { return; } else { newNode->inputMethodGRef = newX11InputMethodGRef; newNode->next = x11InputMethodGRefListHead; x11InputMethodGRefListHead = newNode; } } /* * Remove the global reference from the list. */ static void removeX11InputMethodGRefFromList(jobject x11InputMethodGRef) { X11InputMethodGRefNode *pX11InputMethodGRef = NULL; X11InputMethodGRefNode *cX11InputMethodGRef = x11InputMethodGRefListHead; if (x11InputMethodGRefListHead == NULL || x11InputMethodGRef == NULL) { return; } /* cX11InputMethodGRef always refers to the current node while pX11InputMethodGRef refers to the previous node. */ while (cX11InputMethodGRef != NULL) { if (cX11InputMethodGRef->inputMethodGRef == x11InputMethodGRef) { break; } pX11InputMethodGRef = cX11InputMethodGRef; cX11InputMethodGRef = cX11InputMethodGRef->next; } if (cX11InputMethodGRef == NULL) { return; /* Not found. */ } if (cX11InputMethodGRef == x11InputMethodGRefListHead) { x11InputMethodGRefListHead = x11InputMethodGRefListHead->next; } else { pX11InputMethodGRef->next = cX11InputMethodGRef->next; } free(cX11InputMethodGRef); return; } #endif /* RESUME_ENABLE */ static X11InputMethodData * getX11InputMethodData(JNIEnv * env, jobject imInstance) { X11InputMethodData *pX11IMData = (X11InputMethodData *)JNU_GetLongFieldAsPtr(env, imInstance, x11InputMethodIDs.pData); /* * In case the XIM server was killed somehow, reset X11InputMethodData. */ if (X11im == NULL && pX11IMData != NULL) { JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, "flushText", "()V"); JNU_CHECK_EXCEPTION_RETURN(env, NULL); #if defined(AIX) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } #endif /* IMPORTANT: The order of the following calls is critical since "imInstance" may point to the global reference itself, if "freeX11InputMethodData" is called first, the global reference will be destroyed and "setX11InputMethodData" will in fact fail silently. So pX11IMData will not be set to NULL. This could make the original java object refers to a deleted pX11IMData object. */ setX11InputMethodData(env, imInstance, NULL); freeX11InputMethodData(env, pX11IMData); pX11IMData = NULL; } return pX11IMData; } static void setX11InputMethodData(JNIEnv * env, jobject imInstance, X11InputMethodData *pX11IMData) { JNU_SetLongFieldFromPtr(env, imInstance, x11InputMethodIDs.pData, pX11IMData); } /* this function should be called within AWT_LOCK() */ static void destroyX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData) { /* * Destroy XICs */ if (pX11IMData == NULL) { return; } if (pX11IMData->ic_active != (XIC)0) { XUnsetICFocus(pX11IMData->ic_active); XDestroyIC(pX11IMData->ic_active); if (pX11IMData->ic_active != pX11IMData->ic_passive) { if (pX11IMData->ic_passive != (XIC)0) { XUnsetICFocus(pX11IMData->ic_passive); XDestroyIC(pX11IMData->ic_passive); } pX11IMData->ic_passive = (XIC)0; pX11IMData->current_ic = (XIC)0; } } freeX11InputMethodData(env, pX11IMData); } static void freeX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData) { #if defined(__linux__) || defined(MACOSX) || defined(AIX) if (pX11IMData->statusWindow != NULL){ StatusWindow *sw = pX11IMData->statusWindow; XFreeGC(awt_display, sw->lightGC); XFreeGC(awt_display, sw->dimGC); XFreeGC(awt_display, sw->bgGC); XFreeGC(awt_display, sw->fgGC); if (sw->fontset != NULL) { XFreeFontSet(awt_display, sw->fontset); } XDestroyWindow(awt_display, sw->w); #if defined(AIX) if (pX11IMData->statusWindow->peText){ free((void *)pX11IMData->statusWindow->peText); pX11IMData->statusWindow->peText = NULL; } if (pX11IMData->statusWindow->peAttr){ free((void *)pX11IMData->statusWindow->peAttr); pX11IMData->statusWindow->peAttr = NULL; } #endif free((void*)sw); } #endif if (pX11IMData->callbacks) free((void *)pX11IMData->callbacks); if (env) { #if defined(RESUME_ENABLE) /* Remove the global reference from the list, so that the callback function or whoever refers to it could know. */ removeX11InputMethodGRefFromList(pX11IMData->x11inputmethod); #endif (*env)->DeleteGlobalRef(env, pX11IMData->x11inputmethod); } #if !defined(AIX) if (pX11IMData->lookup_buf) { free((void *)pX11IMData->lookup_buf); } #endif free((void *)pX11IMData); } /* * Sets or unsets the focus to the given XIC. */ static void setXICFocus(XIC ic, unsigned short req) { if (ic == NULL) { (void)fprintf(stderr, "Couldn't find X Input Context\n"); return; } if (req == 1) XSetICFocus(ic); else XUnsetICFocus(ic); } /* * Sets the focus window to the given XIC. */ static void setXICWindowFocus(XIC ic, Window w) { if (ic == NULL) { (void)fprintf(stderr, "Couldn't find X Input Context\n"); return; } (void) XSetICValues(ic, XNFocusWindow, w, NULL); } /* * Invokes XmbLookupString() to get something from the XIM. It invokes * X11InputMethod.dispatchCommittedText() if XmbLookupString() returns * committed text. This function is called from handleKeyEvent in canvas.c and * it's under the Motif event loop thread context. * * Buffer usage: There is a bug in XFree86-4.3.0 XmbLookupString implementation, * where it never returns XBufferOverflow. We need to allocate the initial lookup buffer * big enough, so that the possibility that user encounters this problem is relatively * small. When this bug gets fixed, we can make the initial buffer size smaller. * Note that XmbLookupString() sometimes produces a non-null-terminated string. * * Returns True when there is a keysym value to be handled. */ #define INITIAL_LOOKUP_BUF_SIZE 512 Boolean awt_x11inputmethod_lookupString(XKeyPressedEvent *event, KeySym *keysymp) { JNIEnv *env = GetJNIEnv(); X11InputMethodData *pX11IMData = NULL; #if defined(AIX) int buf_len = INITIAL_LOOKUP_BUF_SIZE; char mbbuf[INITIAL_LOOKUP_BUF_SIZE]; char *buf; #endif KeySym keysym = NoSymbol; Status status; int mblen; jstring javastr; XIC ic; Boolean result = True; static Boolean composing = False; /* printf("lookupString: entering...\n"); */ #if defined(RESUME_ENABLE) if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) { currentX11InputMethodInstance = NULL; return False; } #endif pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance); if (pX11IMData == NULL) { #if defined(__linux__) || defined(MACOSX) || defined(AIX) return False; #else return result; #endif } if ((ic = pX11IMData->current_ic) == (XIC)0){ #if defined(__linux__) || defined(MACOSX) || defined(AIX) return False; #else return result; #endif } #if !defined(AIX) /* allocate the lookup buffer at the first invocation */ if (pX11IMData->lookup_buf_len == 0) { pX11IMData->lookup_buf = (char *)malloc(INITIAL_LOOKUP_BUF_SIZE); if (pX11IMData->lookup_buf == NULL) { THROW_OUT_OF_MEMORY_ERROR(); return result; } pX11IMData->lookup_buf_len = INITIAL_LOOKUP_BUF_SIZE; } mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf, pX11IMData->lookup_buf_len - 1, &keysym, &status); #else buf = mbbuf; mblen = XmbLookupString(ic, event, buf, buf_len - 1, &keysym, &status); #endif /* * In case of overflow, a buffer is allocated and it retries * XmbLookupString(). */ if (status == XBufferOverflow) { #if !defined(AIX) free((void *)pX11IMData->lookup_buf); pX11IMData->lookup_buf_len = 0; pX11IMData->lookup_buf = (char *)malloc(mblen + 1); if (pX11IMData->lookup_buf == NULL) { THROW_OUT_OF_MEMORY_ERROR(); return result; } pX11IMData->lookup_buf_len = mblen + 1; mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf, pX11IMData->lookup_buf_len - 1, &keysym, &status); #else buf_len = mblen + 1; buf = (char *)malloc(buf_len); if (buf == NULL) { THROW_OUT_OF_MEMORY_ERROR(); return result; } mblen = XmbLookupString(ic, event, buf, buf_len, &keysym, &status); #endif } #if !defined(AIX) pX11IMData->lookup_buf[mblen] = 0; #else buf[mblen] = 0; #endif /* Get keysym without taking modifiers into account first to map * to AWT keyCode table. */ switch (status) { case XLookupBoth: if (!composing) { if (event->keycode != 0) { *keysymp = keysym; result = False; break; } } composing = False; /*FALLTHRU*/ case XLookupChars: /* printf("lookupString: status=XLookupChars, type=%d, state=%x, keycode=%x, keysym=%x\n", event->type, event->state, event->keycode, keysym); */ #if !defined(AIX) javastr = JNU_NewStringPlatform(env, (const char *)pX11IMData->lookup_buf); #else javastr = JNU_NewStringPlatform(env, (const char *)buf); #endif if (javastr != NULL) { JNU_CallMethodByName(env, NULL, currentX11InputMethodInstance, "dispatchCommittedText", "(Ljava/lang/String;J)V", javastr, event->time); #if defined(AIX) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } #endif } break; case XLookupKeySym: /* printf("lookupString: status=XLookupKeySym, type=%d, state=%x, keycode=%x, keysym=%x\n", event->type, event->state, event->keycode, keysym); */ if (keysym == XK_Multi_key) composing = True; if (! composing) { *keysymp = keysym; result = False; } break; case XLookupNone: /* printf("lookupString: status=XLookupNone, type=%d, state=%x, keycode=%x, keysym=%x\n", event->type, event->state, event->keycode, keysym); */ break; } #if defined(AIX) if (buf != mbbuf) free(buf); #endif return result; } #if defined(__linux__) || defined(MACOSX) || defined(AIX) static StatusWindow *createStatusWindow( Window parent) { StatusWindow *statusWindow; XSetWindowAttributes attrib; unsigned long attribmask; Window containerWindow; Window status; Window child; XWindowAttributes xwa; XWindowAttributes xxwa; /* Variable for XCreateFontSet()*/ char **mclr; int mccr = 0; char *dsr; unsigned long bg, fg, light, dim; int x, y, off_x, off_y, xx, yy; unsigned int w, h, bw, depth; XGCValues values; unsigned long valuemask = 0; /*ignore XGCvalue and use defaults*/ int screen = 0; int i; AwtGraphicsConfigDataPtr adata; extern int awt_numScreens; /*hardcode the size right now, should get the size base on font*/ int width=80, height=22; Window rootWindow; Window *ignoreWindowPtr; unsigned int ignoreUnit; #if defined(AIX) Window grandParent; Window target; XFontSet fontset; fontset = create_fontset(); if (NULL == fontset) return NULL; #endif XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth); attrib.override_redirect = True; attribmask = CWOverrideRedirect; for (i = 0; i < awt_numScreens; i++) { if (RootWindow(dpy, i) == rootWindow) { screen = i; break; } } adata = getDefaultConfig(screen); bg = adata->AwtColorMatch(255, 255, 255, adata); fg = adata->AwtColorMatch(0, 0, 0, adata); light = adata->AwtColorMatch(195, 195, 195, adata); dim = adata->AwtColorMatch(128, 128, 128, adata); #if !defined(AIX) XGetWindowAttributes(dpy, parent, &xwa); #else grandParent=getGrandParent(parent); if (grandParent == 0){ target = parent; }else{ target = grandParent; } XGetWindowAttributes(dpy, target, &xwa); #endif bw = 2; /*xwa.border_width does not have the correct value*/ /*compare the size difference between parent container and shell widget, the diff should be the border frame and title bar height (?)*/ XQueryTree( dpy, #if !defined(AIX) parent, #else target, #endif &rootWindow, &containerWindow, &ignoreWindowPtr, &ignoreUnit); XGetWindowAttributes(dpy, containerWindow, &xxwa); #if !defined(AIX) off_x = (xxwa.width - xwa.width) / 2; off_y = xxwa.height - xwa.height - off_x; /*it's magic:-) */ #else XTranslateCoordinates(dpy, target, xwa.root, 0, 0, &x, &y, &child); if (containerWindow == rootWindow){ off_x = 0; off_y = STATUS_MARGIN; }else{ XGetWindowAttributes(dpy, containerWindow, &xxwa); off_x = (xxwa.width - xwa.width) / 2; /* off_y = xxwa.height - xwa.height - off_x;*/ /*it's magic:-) */ { int cx, cy; XTranslateCoordinates(dpy, containerWindow, xxwa.root, 0, 0, &cx, &cy, &child); off_y = (xxwa.height + cy) - (xwa.height + y) ; } } #endif /*get the size of root window*/ XGetWindowAttributes(dpy, rootWindow, &xxwa); XTranslateCoordinates(dpy, #if !defined(AIX) parent, xwa.root, #else target, xwa.root, #endif xwa.x, xwa.y, &x, &y, &child); xx = x - off_x; yy = y + xwa.height - off_y; if (xx < 0 ){ xx = 0; } if (xx + width > xxwa.width){ xx = xxwa.width - width; } if (yy + height > xxwa.height){ yy = xxwa.height - height; } #if defined(AIX) if ((DefaultVisual(dpy,screen))->class != adata->awt_visInfo.visual->class && adata->awt_visInfo.visual->class == TrueColor) { attrib.colormap = XCreateColormap(dpy, xwa.root, adata->awt_visInfo.visual, AllocNone ); attrib.border_pixel = BlackPixel(dpy, screen) ; attribmask |= CWColormap | CWBorderPixel; } #endif status = XCreateWindow(dpy, xwa.root, xx, yy, width, height, 0, xwa.depth, InputOutput, adata->awt_visInfo.visual, attribmask, &attrib); XSelectInput(dpy, status, ExposureMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask | VisibilityChangeMask); #if defined(AIX) if (grandParent != 0){ long mask; XGetWindowAttributes(dpy, grandParent, &xwa); mask = xwa.your_event_mask | StructureNotifyMask | VisibilityChangeMask | PropertyChangeMask; XSelectInput(dpy, grandParent,mask); } #endif statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow)); if (statusWindow == NULL){ THROW_OUT_OF_MEMORY_ERROR(); return NULL; } statusWindow->w = status; #if !defined(AIX) //12-point font statusWindow->fontset = XCreateFontSet(dpy, "-*-*-medium-r-normal-*-*-120-*-*-*-*", &mclr, &mccr, &dsr); /* In case we didn't find the font set, release the list of missing characters */ if (mccr > 0) { XFreeStringList(mclr); } #else statusWindow->fontset = fontset; #endif statusWindow->parent = parent; #if defined(AIX) statusWindow->grandParent = grandParent; #endif statusWindow->on = False; statusWindow->x = x; statusWindow->y = y; statusWindow->width = xwa.width; statusWindow->height = xwa.height; statusWindow->off_x = off_x; statusWindow->off_y = off_y; statusWindow->bWidth = bw; statusWindow->statusH = height; statusWindow->statusW = width; #if defined(AIX) statusWindow->peTextW = 0; #endif statusWindow->rootH = xxwa.height; statusWindow->rootW = xxwa.width; statusWindow->lightGC = XCreateGC(dpy, status, valuemask, &values); XSetForeground(dpy, statusWindow->lightGC, light); statusWindow->dimGC = XCreateGC(dpy, status, valuemask, &values); XSetForeground(dpy, statusWindow->dimGC, dim); #if !defined(AIX) statusWindow->fgGC = XCreateGC(dpy, status, valuemask, &values); #else statusWindow->fgGC = create_gc(status, FALSE); #endif XSetForeground(dpy, statusWindow->fgGC, fg); #if !defined(AIX) statusWindow->bgGC = XCreateGC(dpy, status, valuemask, &values); #else statusWindow->bgGC = create_gc(status, TRUE); #endif XSetForeground(dpy, statusWindow->bgGC, bg); #if defined(AIX) statusWindow->status_ready = False; wcscpy(statusWindow->status, L""); #endif return statusWindow; } /* This method is to turn off or turn on the status window. */ static void onoffStatusWindow(X11InputMethodData* pX11IMData, Window parent, Bool ON){ XWindowAttributes xwa; Window child; int x, y; StatusWindow *statusWindow = NULL; #if !defined(AIX) if (NULL == currentX11InputMethodInstance || NULL == pX11IMData || #else if (NULL == pX11IMData || #endif NULL == (statusWindow = pX11IMData->statusWindow)){ return; } if (ON == False){ XUnmapWindow(dpy, statusWindow->w); #if !defined(AIX) statusWindow->on = False; #endif return; } #if !defined(AIX) parent = JNU_CallMethodByName(GetJNIEnv(), NULL, pX11IMData->x11inputmethod, #else if (NULL == currentX11InputMethodInstance){ return; } { JNIEnv *env = GetJNIEnv(); parent = JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, #endif "getCurrentParentWindow", "()J").j; #if defined(AIX) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } } #endif if (statusWindow->parent != parent){ statusWindow->parent = parent; } #if !defined(AIX) XGetWindowAttributes(dpy, parent, &xwa); XTranslateCoordinates(dpy, parent, xwa.root, xwa.x, xwa.y, &x, &y, &child); if (statusWindow->x != x || statusWindow->y != y || statusWindow->height != xwa.height){ statusWindow->x = x; statusWindow->y = y; statusWindow->height = xwa.height; x = statusWindow->x - statusWindow->off_x; y = statusWindow->y + statusWindow->height - statusWindow->off_y; if (x < 0 ){ x = 0; } if (x + statusWindow->statusW > statusWindow->rootW){ x = statusWindow->rootW - statusWindow->statusW; } if (y + statusWindow->statusH > statusWindow->rootH){ y = statusWindow->rootH - statusWindow->statusH; } XMoveWindow(dpy, statusWindow->w, x, y); } statusWindow->on = True; XMapWindow(dpy, statusWindow->w); #else if (st_wcslen(statusWindow->status) > 0 || (statusWindow->peText != NULL && st_wcslen(statusWindow->peText) > 0 )){ moveStatusWindow(statusWindow); XMapRaised(dpy, statusWindow->w); } #endif } void paintStatusWindow(StatusWindow *statusWindow){ Window win = statusWindow->w; GC lightgc = statusWindow->lightGC; GC dimgc = statusWindow->dimGC; GC bggc = statusWindow->bgGC; GC fggc = statusWindow->fgGC; int width = statusWindow->statusW; int height = statusWindow->statusH; int bwidth = statusWindow->bWidth; #if defined(AIX) int len; XRectangle logical, ink; if (NULL == statusWindow) return; if ((len = st_wcslen(statusWindow->status)) == 0) return; XwcTextExtents(statusWindow->fontset, statusWindow->status, len, &ink, &logical); width = logical.width; height = logical.height; XFillRectangle(dpy, win, bggc, 0, 0, width+2, height+2); #endif #if !defined(AIX) XFillRectangle(dpy, win, bggc, 0, 0, width, height); /* draw border */ XDrawLine(dpy, win, fggc, 0, 0, width, 0); XDrawLine(dpy, win, fggc, 0, height-1, width-1, height-1); XDrawLine(dpy, win, fggc, 0, 0, 0, height-1); XDrawLine(dpy, win, fggc, width-1, 0, width-1, height-1); XDrawLine(dpy, win, lightgc, 1, 1, width-bwidth, 1); XDrawLine(dpy, win, lightgc, 1, 1, 1, height-2); XDrawLine(dpy, win, lightgc, 1, height-2, width-bwidth, height-2); XDrawLine(dpy, win, lightgc, width-bwidth-1, 1, width-bwidth-1, height-2); XDrawLine(dpy, win, dimgc, 2, 2, 2, height-3); XDrawLine(dpy, win, dimgc, 2, height-3, width-bwidth-1, height-3); XDrawLine(dpy, win, dimgc, 2, 2, width-bwidth-2, 2); XDrawLine(dpy, win, dimgc, width-bwidth, 2, width-bwidth, height-3); #else XDrawLine(dpy, win, fggc, 0, 0, width+2, 0); XDrawLine(dpy, win, fggc, 0, height+2, width+2, height+2); XDrawLine(dpy, win, fggc, 0, 0, 0, height+2); XDrawLine(dpy, win, fggc, width+2, 0, width+2, height+2); #endif if (statusWindow->fontset){ #if !defined(AIX) XmbDrawString(dpy, win, statusWindow->fontset, fggc, bwidth + 2, height - bwidth - 4, #else XwcDrawString(dpy, win, statusWindow->fontset, fggc, -logical.x + 1, -logical.y + 1, #endif statusWindow->status, #if !defined(AIX) strlen(statusWindow->status)); #else st_wcslen(statusWindow->status)); #endif } else{ /*too bad we failed to create a fontset for this locale*/ XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4, "[InputMethod ON]", strlen("[InputMethod ON]")); } } #if !defined(AIX) void statusWindowEventHandler(XEvent event){ #else Bool statusWindowEventHandler(XEvent event){ #endif JNIEnv *env = GetJNIEnv(); X11InputMethodData *pX11IMData = NULL; StatusWindow *statusWindow; #if defined(RESUME_ENABLE) if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) { currentX11InputMethodInstance = NULL; #if !defined(AIX) return; #else return False; #endif } #endif if (NULL == currentX11InputMethodInstance || NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance)) #if !defined(AIX) || NULL == (statusWindow = pX11IMData->statusWindow) || statusWindow->w != event.xany.window){ return; #else || NULL == (statusWindow = pX11IMData->statusWindow)){ return False; #endif } #if defined(AIX) if (statusWindow->w == event.xany.window){ #endif switch (event.type){ case Expose: paintStatusWindow(statusWindow); #if defined(AIX) if (statusWindow->peText) draw_preedit(statusWindow); arrange_window_stack(statusWindow); #endif break; #if !defined(AIX) case MapNotify: #endif case ConfigureNotify: #if defined(AIX) case VisibilityNotify: arrange_window_stack(statusWindow); #endif #if !defined(AIX) { /*need to reset the stackMode...*/ XWindowChanges xwc; int value_make = CWStackMode; xwc.stack_mode = TopIf; XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); } #endif break; /* case UnmapNotify: case VisibilityNotify: break; */ default: break; } #if defined(AIX) return True; }else if ((statusWindow->parent == event.xany.window) ||(statusWindow->grandParent && statusWindow->grandParent == event.xany.window)){ switch (event.type){ case MapNotify: if (statusWindow->on){ onoffStatusWindow(pX11IMData, statusWindow->parent, True); } break; case UnmapNotify: onoffStatusWindow(pX11IMData, 0, False); break; case VisibilityNotify: if (statusWindow->on){ arrange_window_stack(statusWindow); } break; case ConfigureNotify: if (statusWindow->grandParent && statusWindow->on){ moveStatusWindow(statusWindow); } case PropertyNotify: if (statusWindow->on){ arrange_window_stack(statusWindow); } break; default: break; } } return False; #endif } static void adjustStatusWindow(Window shell){ JNIEnv *env = GetJNIEnv(); X11InputMethodData *pX11IMData = NULL; StatusWindow *statusWindow; if (NULL == currentX11InputMethodInstance #if defined(RESUME_ENABLE) || !isX11InputMethodGRefInList(currentX11InputMethodInstance) #endif || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance)) || NULL == (statusWindow = pX11IMData->statusWindow) || !statusWindow->on) { return; } #if defined(AIX) moveStatusWindow(statusWindow); #endif #if !defined(AIX) { XWindowAttributes xwa; int x, y; Window child; XGetWindowAttributes(dpy, shell, &xwa); XTranslateCoordinates(dpy, shell, xwa.root, xwa.x, xwa.y, &x, &y, &child); if (statusWindow->x != x || statusWindow->y != y || statusWindow->height != xwa.height){ statusWindow->x = x; statusWindow->y = y; statusWindow->height = xwa.height; x = statusWindow->x - statusWindow->off_x; y = statusWindow->y + statusWindow->height - statusWindow->off_y; if (x < 0 ){ x = 0; } if (x + statusWindow->statusW > statusWindow->rootW){ x = statusWindow->rootW - statusWindow->statusW; } if (y + statusWindow->statusH > statusWindow->rootH){ y = statusWindow->rootH - statusWindow->statusH; } XMoveWindow(dpy, statusWindow->w, x, y); } } #endif } #endif /* __linux__ || MACOSX || AIX */ /* * Creates two XICs, one for active clients and the other for passive * clients. All information on those XICs are stored in the * X11InputMethodData given by the pX11IMData parameter. * * For active clients: Try to use preedit callback to support * on-the-spot. If tc is not null, the XIC to be created will * share the Status Area with Motif widgets (TextComponents). If the * preferable styles can't be used, fallback to root-window styles. If * root-window styles failed, fallback to None styles. * * For passive clients: Try to use root-window styles. If failed, * fallback to None styles. */ static Bool createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w) { XVaNestedList preedit = NULL; XVaNestedList status = NULL; XIMStyle on_the_spot_styles = XIMPreeditCallbacks, #if defined(AIX) in_place_styles = 0, #endif active_styles = 0, passive_styles = 0, no_styles = 0; XIMCallback *callbacks; unsigned short i; XIMStyles *im_styles; char *ret = NULL; #if defined(AIX) Bool passiveStatusWindow = False; pX11IMData->statusWindow = NULL; #endif if (X11im == NULL) { return False; } if (!w) { return False; } #if defined(AIX) if (getenv("IBMJAVA_PASSIVE") == NULL) { passiveStatusWindow = False; } else { passiveStatusWindow = True; } if (isNativeIm()) { passiveStatusWindow = True; } #endif ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL); if (ret != NULL) { jio_fprintf(stderr,"XGetIMValues: %s\n",ret); return FALSE ; } #if defined(__linux__) || defined(MACOSX) || defined(AIX) on_the_spot_styles |= XIMStatusNothing; /*kinput does not support XIMPreeditCallbacks and XIMStatusArea at the same time, so use StatusCallback to draw the status ourself */ for (i = 0; i < im_styles->count_styles; i++) { if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) { on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks); break; } } #else /*! __linux__ && !MACOSX && !AIX */ on_the_spot_styles |= XIMStatusNothing; #endif /* __linux__ || MACOSX || AIX */ #if !defined(AIX) for (i = 0; i < im_styles->count_styles; i++) { active_styles |= im_styles->supported_styles[i] & on_the_spot_styles; passive_styles |= im_styles->supported_styles[i] & ROOT_WINDOW_STYLES; no_styles |= im_styles->supported_styles[i] & NO_STYLES; } #else for (i = 0; i < im_styles->count_styles; i++) { if (im_styles->supported_styles[i] == on_the_spot_styles) active_styles = im_styles->supported_styles[i]; if (im_styles->supported_styles[i] == ROOT_WINDOW_STYLES) passive_styles = im_styles->supported_styles[i]; if (im_styles->supported_styles[i] == IN_PLACE_STYLES) { in_place_styles = im_styles->supported_styles[i]; } if (im_styles->supported_styles[i] == NO_STYLES) no_styles = im_styles->supported_styles[i]; } #endif XFree(im_styles); if (active_styles != on_the_spot_styles) { if (passive_styles == ROOT_WINDOW_STYLES) active_styles = passive_styles; else { #if defined(AIX) if (in_place_styles == IN_PLACE_STYLES){ active_styles = passive_styles = IN_PLACE_STYLES; } else { #endif if (no_styles == NO_STYLES) active_styles = passive_styles = NO_STYLES; else active_styles = passive_styles = 0; #if defined(AIX) } #endif } } else { #if defined(AIX) if (!passiveStatusWindow) { #endif if (passive_styles != ROOT_WINDOW_STYLES) { if (no_styles == NO_STYLES) active_styles = passive_styles = NO_STYLES; else active_styles = passive_styles = 0; } #if defined(AIX) } else passive_styles = active_styles; #endif } if (active_styles == on_the_spot_styles) { #if !defined(AIX) pX11IMData->ic_passive = XCreateIC(X11im, XNClientWindow, w, XNFocusWindow, w, XNInputStyle, passive_styles, NULL); #endif callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS); if (callbacks == (XIMCallback *)NULL) return False; pX11IMData->callbacks = callbacks; for (i = 0; i < NCALLBACKS; i++, callbacks++) { callbacks->client_data = (XPointer) pX11IMData->x11inputmethod; callbacks->callback = callback_funcs[i]; } callbacks = pX11IMData->callbacks; preedit = (XVaNestedList)XVaCreateNestedList(0, XNPreeditStartCallback, &callbacks[PreeditStartIndex], XNPreeditDoneCallback, &callbacks[PreeditDoneIndex], XNPreeditDrawCallback, &callbacks[PreeditDrawIndex], XNPreeditCaretCallback, &callbacks[PreeditCaretIndex], NULL); if (preedit == (XVaNestedList)NULL) goto err; #if defined(__linux__) || defined(MACOSX) || defined(AIX) /*always try XIMStatusCallbacks for active client...*/ { #if defined(AIX) if (on_the_spot_styles & XIMStatusCallbacks) { #endif status = (XVaNestedList)XVaCreateNestedList(0, XNStatusStartCallback, &callbacks[StatusStartIndex], XNStatusDoneCallback, &callbacks[StatusDoneIndex], XNStatusDrawCallback, &callbacks[StatusDrawIndex], NULL); if (status == NULL) goto err; #if defined(AIX) } #endif pX11IMData->statusWindow = createStatusWindow(w); pX11IMData->ic_active = XCreateIC(X11im, XNClientWindow, w, XNFocusWindow, w, XNInputStyle, active_styles, XNPreeditAttributes, preedit, XNStatusAttributes, status, NULL); #if defined(AIX) if (NULL != pX11IMData->statusWindow) { pX11IMData->statusWindow->status_ready = True; } #endif XFree((void *)status); XFree((void *)preedit); } #else /* !__linux__ && !MACOSX && !AIX */ pX11IMData->ic_active = XCreateIC(X11im, XNClientWindow, w, XNFocusWindow, w, XNInputStyle, active_styles, XNPreeditAttributes, preedit, NULL); XFree((void *)preedit); #endif /* __linux__ || MACOSX || AIX */ #if defined(AIX) if (passiveStatusWindow) { pX11IMData->ic_passive = pX11IMData->ic_active; } else { pX11IMData->ic_passive = XCreateIC(X11im, XNClientWindow, w, XNFocusWindow, w, XNInputStyle, passive_styles, NULL); } #endif } else { pX11IMData->ic_active = XCreateIC(X11im, XNClientWindow, w, XNFocusWindow, w, XNInputStyle, active_styles, NULL); pX11IMData->ic_passive = pX11IMData->ic_active; } #if defined(AIX) // The code set the IC mode that the preedit state is not initialied // at XmbResetIC. This attribute can be set at XCreateIC. I separately // set the attribute to avoid the failure of XCreateIC at some platform // which does not support the attribute. if (pX11IMData->ic_active != 0) XSetICValues(pX11IMData->ic_active, XNResetState, XIMPreserveState, NULL); if (pX11IMData->ic_passive != 0 && pX11IMData->ic_active != pX11IMData->ic_passive) XSetICValues(pX11IMData->ic_passive, XNResetState, XIMInitialState, NULL); pX11IMData->passiveStatusWindow = passiveStatusWindow; #endif if (pX11IMData->ic_active == (XIC)0 || pX11IMData->ic_passive == (XIC)0) { return False; } #if !defined(AIX) /* * Use commit string call back if possible. * This will ensure the correct order of preedit text and commit text */ { XIMCallback cb; cb.client_data = (XPointer) pX11IMData->x11inputmethod; cb.callback = (XIMProc) CommitStringCallback; XSetICValues (pX11IMData->ic_active, XNCommitStringCallback, &cb, NULL); if (pX11IMData->ic_active != pX11IMData->ic_passive) { XSetICValues (pX11IMData->ic_passive, XNCommitStringCallback, &cb, NULL); } } #endif #if defined(RESUME_ENABLE) /* Add the global reference object to X11InputMethod to the list. */ addToX11InputMethodGRefList(pX11IMData->x11inputmethod); #endif #if defined(AIX) /* Unset focus to avoid unexpected IM on */ setXICFocus(pX11IMData->ic_active, False); if (pX11IMData->ic_active != pX11IMData->ic_passive) setXICFocus(pX11IMData->ic_passive, False); #endif return True; err: if (preedit) XFree((void *)preedit); THROW_OUT_OF_MEMORY_ERROR(); return False; } #if !defined(AIX) static void #else static int #endif PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data) { #if defined(AIX) JNIEnv *env = GetJNIEnv(); X11InputMethodData *pX11IMData; #endif /*ARGSUSED*/ #if !defined(AIX) /* printf("Native: PreeditCaretCallback\n"); */ #else /* printf("Native: PreeditStartCallback\n"); */ pX11IMData = getX11InputMethodData(env, (jobject)client_data); if (pX11IMData == NULL || pX11IMData->statusWindow == NULL) { return 0; } resetPassivePreeditText(pX11IMData->statusWindow); return -1; /* unlimited length for preedit text */ #endif } static void PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data) { #if defined(AIX) JNIEnv *env = GetJNIEnv(); X11InputMethodData *pX11IMData; #endif /*ARGSUSED*/ #if !defined(AIX) /* printf("Native: StatusStartCallback\n"); */ #else /* printf("Native: PreeditDoneCallback\n"); */ pX11IMData = getX11InputMethodData(env, (jobject)client_data); if (pX11IMData == NULL) { return; } if (!pX11IMData->isActiveClient) { resetPassivePreeditText(pX11IMData->statusWindow); shrink_status(pX11IMData->statusWindow); } else{ JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, "clearComposedText", "(J)V", awt_util_nowMillisUTC()); if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } } #endif } /* * Translate the preedit draw callback items to Java values and invoke * X11InputMethod.dispatchComposedText(). * * client_data: X11InputMethod object */ static void PreeditDrawCallback(XIC ic, XPointer client_data, XIMPreeditDrawCallbackStruct *pre_draw) { JNIEnv *env = GetJNIEnv(); X11InputMethodData *pX11IMData = NULL; jmethodID x11imMethodID; XIMText *text; jstring javastr = NULL; jintArray style = NULL; /* printf("Native: PreeditDrawCallback() \n"); */ if (pre_draw == NULL) { return; } AWT_LOCK(); #if defined(RESUME_ENABLE) if (!isX11InputMethodGRefInList((jobject)client_data)) { if ((jobject)client_data == currentX11InputMethodInstance) { currentX11InputMethodInstance = NULL; } goto finally; } #endif if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) { goto finally; } #if defined(AIX) if (!pX11IMData->isActiveClient){ if (ic == pX11IMData->ic_passive) { preedit_draw_passive(pX11IMData, pre_draw); } goto finally; } #endif if ((text = pre_draw->text) != NULL) { #if defined(AIX) if (is_text_available(text)) { #endif if (text->string.multi_byte != NULL) { if (pre_draw->text->encoding_is_wchar == False) { javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte); if (javastr == NULL) { goto finally; } } else { char *mbstr = wcstombsdmp(text->string.wide_char, text->length); if (mbstr == NULL) { goto finally; } javastr = JNU_NewStringPlatform(env, (const char *)mbstr); free(mbstr); if (javastr == NULL) { goto finally; } } } #if defined(AIX) } #endif if (text->feedback != NULL) { int cnt; jint *tmpstyle; style = (*env)->NewIntArray(env, text->length); if (JNU_IsNull(env, style)) { (*env)->ExceptionClear(env); THROW_OUT_OF_MEMORY_ERROR(); goto finally; } if (sizeof(XIMFeedback) == sizeof(jint)) { /* * Optimization to avoid copying the array */ (*env)->SetIntArrayRegion(env, style, 0, text->length, (jint *)text->feedback); } else { tmpstyle = (jint *)malloc(sizeof(jint)*(text->length)); if (tmpstyle == (jint *) NULL) { THROW_OUT_OF_MEMORY_ERROR(); goto finally; } for (cnt = 0; cnt < (int)text->length; cnt++) tmpstyle[cnt] = text->feedback[cnt]; (*env)->SetIntArrayRegion(env, style, 0, text->length, (jint *)tmpstyle); } } } JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, "dispatchComposedText", "(Ljava/lang/String;[IIIIJ)V", javastr, style, (jint)pre_draw->chg_first, (jint)pre_draw->chg_length, (jint)pre_draw->caret, awt_util_nowMillisUTC()); #if defined(AIX) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } #endif finally: AWT_UNLOCK(); return; } static void PreeditCaretCallback(XIC ic, XPointer client_data, XIMPreeditCaretCallbackStruct *pre_caret) { #if defined(AIX) XIMPreeditDrawCallbackStruct pre_draw; #endif /*ARGSUSED*/ /* printf("Native: PreeditCaretCallback\n"); */ #if defined(AIX) if (pre_caret != NULL && pre_caret->direction == XIMAbsolutePosition) { pre_draw.caret = pre_caret->position; pre_draw.chg_first = 0; pre_draw.chg_length = 0; pre_draw.text = NULL; PreeditDrawCallback(ic, client_data, &pre_draw); } #endif } #if defined(__linux__) || defined(MACOSX) || defined(AIX) static void StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data) { /*ARGSUSED*/ /*printf("StatusStartCallback:\n"); */ } static void StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data) { /*ARGSUSED*/ /*printf("StatusDoneCallback:\n"); */ } static void StatusDrawCallback(XIC ic, XPointer client_data, XIMStatusDrawCallbackStruct *status_draw) { /*ARGSUSED*/ /*printf("StatusDrawCallback:\n"); */ JNIEnv *env = GetJNIEnv(); X11InputMethodData *pX11IMData = NULL; StatusWindow *statusWindow; #if defined(AIX) int value_make = CWX|CWWidth|CWHeight; XRectangle logical, ink; XWindowChanges xwc; int len; #endif AWT_LOCK(); #if defined(RESUME_ENABLE) if (!isX11InputMethodGRefInList((jobject)client_data)) { if ((jobject)client_data == currentX11InputMethodInstance) { currentX11InputMethodInstance = NULL; } goto finally; } #endif if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data)) || NULL == (statusWindow = pX11IMData->statusWindow)){ goto finally; } #if !defined(AIX) currentX11InputMethodInstance = (jobject)client_data; #endif if (status_draw->type == XIMTextType){ XIMText *text = (status_draw->data).text; if (text != NULL){ if (text->string.multi_byte != NULL) { #if !defined(AIX) strncpy(statusWindow->status, text->string.multi_byte, MAX_STATUS_LEN); statusWindow->status[MAX_STATUS_LEN - 1] = '\0'; #else if(!strcmp(text->string.multi_byte," ")){ wcscpy(statusWindow->status, L""); onoffStatusWindow(pX11IMData, 0, False); goto finally; } mbstowcs(statusWindow->status, (const char *)text->string.multi_byte, (size_t)MAX_STATUS_LEN); #endif } else { #if !defined(AIX) char *mbstr = wcstombsdmp(text->string.wide_char, text->length); strncpy(statusWindow->status, mbstr, MAX_STATUS_LEN); statusWindow->status[MAX_STATUS_LEN - 1] = '\0'; #else if (0 == st_wcslen(text->string.wide_char)){ wcscpy(statusWindow->status, L""); onoffStatusWindow(pX11IMData, 0, False); goto finally; } wcsncpy(statusWindow->status, text->string.wide_char, MAX_STATUS_LEN); #endif } #if !defined(AIX) statusWindow->on = True; onoffStatusWindow(pX11IMData, statusWindow->parent, True); paintStatusWindow(statusWindow); #else XwcTextExtents(statusWindow->fontset, statusWindow->status, st_wcslen(statusWindow->status), &ink, &logical); statusWindow->statusW = logical.width + BORDER_MARGIN; statusWindow->statusH = logical.height + BORDER_MARGIN; xwc.x = statusWindow->x - statusWindow->off_x; if (xwc.x < 0 ) xwc.x = 0; xwc.width = statusWindow->statusW; xwc.height = statusWindow->statusH; if (xwc.x + xwc.width > statusWindow->rootW){ xwc.x = statusWindow->rootW - xwc.width; } XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); if (statusWindow->status_ready && statusWindow->on == True){ onoffStatusWindow(pX11IMData, statusWindow->parent, True); } paintStatusWindow(statusWindow); if (statusWindow->peText) draw_preedit(statusWindow); #endif } else { #if !defined(AIX) statusWindow->on = False; #else wcscpy(statusWindow->status, L""); #endif /*just turnoff the status window paintStatusWindow(statusWindow); */ onoffStatusWindow(pX11IMData, 0, False); } } finally: AWT_UNLOCK(); } #endif /* __linux__ || MACOSX */ #if !defined(AIX) static void CommitStringCallback(XIC ic, XPointer client_data, XPointer call_data) { JNIEnv *env = GetJNIEnv(); XIMText * text = (XIMText *)call_data; X11InputMethodData *pX11IMData = NULL; jstring javastr; AWT_LOCK(); if (!isX11InputMethodGRefInList((jobject)client_data)) { if ((jobject)client_data == currentX11InputMethodInstance) { currentX11InputMethodInstance = NULL; } goto finally; } if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) { goto finally; } currentX11InputMethodInstance = (jobject)client_data; if (text->encoding_is_wchar == False) { javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte); } else { char *mbstr = wcstombsdmp(text->string.wide_char, text->length); if (mbstr == NULL) { goto finally; } javastr = JNU_NewStringPlatform(env, (const char *)mbstr); free(mbstr); } if (javastr != NULL) { JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, "dispatchCommittedText", "(Ljava/lang/String;J)V", javastr, awt_util_nowMillisUTC()); } finally: AWT_UNLOCK(); } #endif #if defined(RESUME_ENABLE) static void OpenXIMCallback(Display *display, XPointer client_data, XPointer call_data) { XIMCallback ximCallback; X11im = XOpenIM(display, NULL, NULL, NULL); if (X11im == NULL) { return; } ximCallback.callback = (XIMProc)DestroyXIMCallback; ximCallback.client_data = NULL; XSetIMValues(X11im, XNDestroyCallback, &ximCallback, NULL); } static void DestroyXIMCallback(XIM im, XPointer client_data, XPointer call_data) { /* mark that XIM server was destroyed */ X11im = NULL; JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); /* free the old pX11IMData and set it to null. this also avoids crashing * the jvm if the XIM server reappears */ X11InputMethodData *pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance); } #endif /* RESUME_ENABLE */ /* * Class: sun_awt_X11InputMethod * Method: initIDs * Signature: ()V */ /* This function gets called from the static initializer for X11InputMethod.java to initialize the fieldIDs for fields that may be accessed from C */ JNIEXPORT void JNICALL Java_sun_awt_X11InputMethod_initIDs(JNIEnv *env, jclass cls) { x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"); } JNIEXPORT jboolean JNICALL Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env, jobject this, jlong display) { Bool registered; AWT_LOCK(); dpy = (Display *)jlong_to_ptr(display); #ifndef RESUME_ENABLE if (X11im == NULL) { X11im = XOpenIM(dpy, NULL, NULL, NULL); } #else /* !RESUME_ENABLE */ /* Use IMInstantiate call back only on Linux, as there is a bug in Solaris (4768335) */ #if defined(__linux__) || defined(MACOSX) registered = XRegisterIMInstantiateCallback(dpy, NULL, NULL, NULL, (XIDProc)OpenXIMCallback, NULL); if (!registered) { /* directly call openXIM callback */ #endif OpenXIMCallback(dpy, NULL, NULL); #if defined(__linux__) || defined(MACOSX) } #endif #endif /* RESUME_ENABLE */ AWT_UNLOCK(); return JNI_TRUE; } JNIEXPORT jboolean JNICALL Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env, jobject this, jlong window) { X11InputMethodData *pX11IMData; jobject globalRef; XIC ic; AWT_LOCK(); if (!window) { JNU_ThrowNullPointerException(env, "NullPointerException"); AWT_UNLOCK(); return JNI_FALSE; } pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData)); if (pX11IMData == NULL) { THROW_OUT_OF_MEMORY_ERROR(); AWT_UNLOCK(); return JNI_FALSE; } globalRef = (*env)->NewGlobalRef(env, this); pX11IMData->x11inputmethod = globalRef; #if defined(__linux__) || defined(MACOSX) || defined(AIX) pX11IMData->statusWindow = NULL; #endif /* __linux__ || MACOSX || AIX */ #if !defined(AIX) pX11IMData->lookup_buf = 0; pX11IMData->lookup_buf_len = 0; #else setX11InputMethodData(env, this, pX11IMData); #endif if (createXIC(env, pX11IMData, (Window)window) == False) { destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData); pX11IMData = (X11InputMethodData *) NULL; #if defined(AIX) setX11InputMethodData(env, this, pX11IMData); #endif if ((*env)->ExceptionCheck(env)) { goto finally; } } #if !defined(AIX) setX11InputMethodData(env, this, pX11IMData); #endif finally: AWT_UNLOCK(); return (pX11IMData != NULL); } JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env, jobject this, jlong w, jboolean req, jboolean active) { X11InputMethodData *pX11IMData; AWT_LOCK(); pX11IMData = getX11InputMethodData(env, this); if (pX11IMData == NULL) { AWT_UNLOCK(); return; } if (req) { if (!w) { AWT_UNLOCK(); return; } #if defined(AIX) pX11IMData->isActiveClient = active; #endif pX11IMData->current_ic = active ? pX11IMData->ic_active : pX11IMData->ic_passive; /* * On Solaris2.6, setXICWindowFocus() has to be invoked * before setting focus. */ #if defined(AIX) get_current_focus(pX11IMData->current_ic); /* workaround for kinput2 and SCIM */ if (currentFocusWindow != w) { #endif setXICWindowFocus(pX11IMData->current_ic, w); setXICFocus(pX11IMData->current_ic, req); currentX11InputMethodInstance = pX11IMData->x11inputmethod; currentFocusWindow = w; #if defined(AIX) } else { #endif #if defined(__linux__) || defined(MACOSX) if (active && pX11IMData->statusWindow && pX11IMData->statusWindow->on) #endif #if defined(AIX) setXICFocus(pX11IMData->current_ic, req); } if ((active || pX11IMData->passiveStatusWindow) && (pX11IMData->statusWindow && pX11IMData->statusWindow->on)) #endif #if defined(__linux__) || defined(MACOSX) || defined(AIX) onoffStatusWindow(pX11IMData, w, True); #endif } else { currentX11InputMethodInstance = NULL; currentFocusWindow = 0; #if defined(__linux__) || defined(MACOSX) || defined(AIX) onoffStatusWindow(pX11IMData, 0, False); if (pX11IMData->current_ic != NULL) #endif setXICFocus(pX11IMData->current_ic, req); pX11IMData->current_ic = (XIC)0; } XFlush(dpy); AWT_UNLOCK(); } JNIEXPORT void JNICALL Java_sun_awt_X11InputMethod_turnoffStatusWindow(JNIEnv *env, jobject this) { #if defined(__linux__) || defined(MACOSX) || defined(AIX) X11InputMethodData *pX11IMData; StatusWindow *statusWindow; AWT_LOCK(); if (NULL == currentX11InputMethodInstance #if defined(RESUME_ENABLE) || !isX11InputMethodGRefInList(currentX11InputMethodInstance) #endif || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance)) || NULL == (statusWindow = pX11IMData->statusWindow) || !statusWindow->on ){ AWT_UNLOCK(); return; } onoffStatusWindow(pX11IMData, 0, False); #if defined(AIX) statusWindow->on = False; #endif AWT_UNLOCK(); #endif } JNIEXPORT void JNICALL Java_sun_awt_X11InputMethod_disposeXIC(JNIEnv *env, jobject this) { X11InputMethodData *pX11IMData = NULL; AWT_LOCK(); pX11IMData = getX11InputMethodData(env, this); if (pX11IMData == NULL) { AWT_UNLOCK(); return; } setX11InputMethodData(env, this, NULL); if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) { currentX11InputMethodInstance = NULL; currentFocusWindow = 0; } destroyX11InputMethodData(env, pX11IMData); AWT_UNLOCK(); } JNIEXPORT jstring JNICALL Java_sun_awt_X11InputMethod_resetXIC(JNIEnv *env, jobject this) { X11InputMethodData *pX11IMData; char *xText = NULL; jstring jText = (jstring)0; AWT_LOCK(); pX11IMData = getX11InputMethodData(env, this); if (pX11IMData == NULL) { AWT_UNLOCK(); return jText; } if (pX11IMData->current_ic) #if defined(AIX) { if (!isPreeditStateActive(pX11IMData->current_ic)) { xText = NULL; } else { if (!(pX11IMData->forceReset)) setXICFocus(pX11IMData->current_ic, FALSE); #endif xText = XmbResetIC(pX11IMData->current_ic); #if defined(AIX) if (!(pX11IMData->forceReset)) setXICFocus(pX11IMData->current_ic, TRUE); } } #endif else { /* * If there is no reference to the current XIC, try to reset both XICs. */ #if defined(AIX) if (!isPreeditStateActive(pX11IMData->ic_active)) xText = NULL; else #endif xText = XmbResetIC(pX11IMData->ic_active); /*it may also means that the real client component does not have focus -- has been deactivated... its xic should not have the focus, bug#4284651 showes reset XIC for htt may bring the focus back, so de-focus it again. */ setXICFocus(pX11IMData->ic_active, FALSE); if (pX11IMData->ic_active != pX11IMData->ic_passive) { #if !defined(AIX) char *tmpText = XmbResetIC(pX11IMData->ic_passive); #else char *tmpText; if (!isPreeditStateActive(pX11IMData->ic_passive)) tmpText = NULL; else tmpText = XmbResetIC(pX11IMData->ic_passive); #endif setXICFocus(pX11IMData->ic_passive, FALSE); if (xText == (char *)NULL && tmpText) xText = tmpText; } } if (xText != NULL) { jText = JNU_NewStringPlatform(env, (const char *)xText); XFree((void *)xText); } #if defined(AIX) /* workaround * Some IME do not call PreeditDoneCallback routine even * when XmbResetIC is called. I force to reset the preedit string. */ if (!pX11IMData->isActiveClient) { resetPassivePreeditText(pX11IMData->statusWindow); shrink_status(pX11IMData->statusWindow); } else { JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, "clearComposedText", "()V"); if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } } #endif AWT_UNLOCK(); return jText; } /* * Class: sun_awt_X11InputMethod * Method: setCompositionEnabledNative * Signature: (ZJ)V * * This method tries to set the XNPreeditState attribute associated with the current * XIC to the passed in 'enable' state. * * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the * 'enable' state; Otherwise, if XSetICValues fails to set this attribute, * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this * method fails due to other reasons. * */ JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_setCompositionEnabledNative (JNIEnv *env, jobject this, jboolean enable) { X11InputMethodData *pX11IMData; char * ret = NULL; #if defined(AIX) XVaNestedList pr_atrb; #endif AWT_LOCK(); pX11IMData = getX11InputMethodData(env, this); if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { AWT_UNLOCK(); return JNI_FALSE; } #if !defined(AIX) ret = XSetICValues(pX11IMData->current_ic, XNPreeditState, (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL); AWT_UNLOCK(); if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) { JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); } #else pr_atrb = XVaCreateNestedList(0, XNPreeditState, (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL); ret = XSetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL); XFree((void *)pr_atrb); AWT_UNLOCK(); if ((ret != 0) && ((strcmp(ret, XNPreeditAttributes) == 0) || (strcmp(ret, XNPreeditState) == 0))) { JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); } #endif return (jboolean)(ret == 0); } /* * Class: sun_awt_X11InputMethod * Method: isCompositionEnabledNative * Signature: (J)Z * * This method tries to get the XNPreeditState attribute associated with the current XIC. * * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException * will be thrown. JNI_FALSE is returned if this method fails due to other reasons. * */ JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_isCompositionEnabledNative (JNIEnv *env, jobject this) { X11InputMethodData *pX11IMData = NULL; char * ret = NULL; #if !defined(AIX) XIMPreeditState state; #else XIMPreeditState state = XIMPreeditUnKnown; XVaNestedList pr_atrb; #endif AWT_LOCK(); pX11IMData = getX11InputMethodData(env, this); if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { AWT_UNLOCK(); return JNI_FALSE; } #if !defined(AIX) ret = XGetICValues(pX11IMData->current_ic, XNPreeditState, &state, NULL); AWT_UNLOCK(); if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) { JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); return JNI_FALSE; } #else pr_atrb = XVaCreateNestedList(0, XNPreeditState, &state, NULL); ret = XGetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL); XFree((void *)pr_atrb); AWT_UNLOCK(); if ((ret != 0) && ((strcmp(ret, XNPreeditAttributes) == 0) || (strcmp(ret, XNPreeditState) == 0))) { JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); return JNI_FALSE; } #endif return (jboolean)(state == XIMPreeditEnable); } JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow (JNIEnv *env, jobject this, jlong window) { #if defined(__linux__) || defined(MACOSX) AWT_LOCK(); adjustStatusWindow(window); AWT_UNLOCK(); #endif } #if defined(AIX) /* * The following functions are IBM's enhancement. */ JNIEXPORT void JNICALL Java_sun_awt_X11InputMethod_setStatusAreaVisible(JNIEnv *env, jobject this, jboolean value, jlong data) { X11InputMethodData *pX11IMData; pX11IMData = getX11InputMethodData(env, this); if (NULL == pX11IMData) return; if (NULL == pX11IMData->statusWindow) return; if ((int)value){ pX11IMData->statusWindow->on = True; }else{ pX11IMData->statusWindow->on = False; } return; } /* return the string length without trailing spaces */ /* work around code for Japanese AIXIM is implemented. */ static int st_wcslen(wchar_t *string) { int len = (int32_t)wcslen(string); if (len == 0) return 0; for (len--;len >= 0; len--) { if (!iswspace((wint_t) string[len])) break; } return len+1; } /* * Checks whether given XIMText contains a string data. */ static Bool is_text_available(XIMText * text) { if (text == NULL || text->length==0) return False; if (text->encoding_is_wchar) { if(text->string.wide_char[0] == L'\0') return False; } else { if (text->string.multi_byte[0] == '\0') return False; } return True; } /* * check if preedit status is active */ static Bool isPreeditStateActive(XIC ic) { XIMPreeditState state = XIMPreeditUnKnown; XVaNestedList pr_atrb; char* nosupportAttr; if (ic == NULL) return False; pr_atrb = XVaCreateNestedList(0,XNPreeditState,&state,NULL); nosupportAttr=XGetICValues(ic,XNPreeditAttributes,pr_atrb,NULL); XFree(pr_atrb); if (nosupportAttr==NULL && state & XIMPreeditDisable) return False; else return True; } static void * buf_insert(void * src, void * insert, int size, int src_len, int ins_len, int offset) { char *temp; temp = realloc(src, size*(src_len+ins_len+1)); if (temp == NULL) { THROW_OUT_OF_MEMORY_ERROR(); return src; } if (offset != src_len) { memmove(&temp[size*(offset+ins_len)], &((char *)temp)[size*offset], size*(src_len-offset)); } memcpy(&temp[size*offset], insert, size*ins_len); return (void *)temp; } static void * handle_buffer(void * source, void * insert, int size,int src_len, int ins_len, int del_len, int offset) { void * temp = source; if(del_len > 0) { if (del_len == ins_len) { memcpy(&((char *)source)[size*offset], insert, size*ins_len); return source; } else if (src_len > offset+del_len) { memmove(&((char *)source)[size*offset], &((char *)source)[size*(offset+del_len)], size*(src_len-offset-del_len)); } } if(ins_len > 0) { temp = buf_insert(source, insert, size, src_len, ins_len, offset); } return temp; } /* * Display the given preedit text to the root window which is ownd by * myself. All of the character is converted to wide char. * this function is used for the passive client. */ static void preedit_draw_passive(X11InputMethodData *pX11IMData, XIMPreeditDrawCallbackStruct *pre_draw) { XIMText *text; wchar_t *tempbuf = NULL; StatusWindow *statusWindow; wchar_t *cur_text; unsigned long *cur_attr; int cur_len = 0; int chg_len = pre_draw->chg_length; int chg_1st = pre_draw->chg_first; if (NULL == (statusWindow = pX11IMData->statusWindow)) return; cur_text = statusWindow->peText; cur_attr = statusWindow->peAttr; if (cur_text == NULL && pre_draw->text == NULL) return; if (cur_text != NULL) cur_len = (int32_t)wcslen(cur_text); text = pre_draw->text; if (text == NULL) { /* delete only */ if (cur_len > chg_1st+chg_len) { memmove(&cur_text[chg_1st], &cur_text[chg_1st+chg_len], sizeof(wchar_t)*(cur_len-chg_1st-chg_len)); memmove(&cur_attr[chg_1st], &cur_attr[chg_1st+chg_len], sizeof(long)*(cur_len-chg_1st-chg_len)); } if ((pre_draw->chg_length <= cur_len ) && (pre_draw->chg_length >0)) cur_text[cur_len-pre_draw->chg_length] =L'\0'; } else { /* insert or replace */ int ins_len = 0; void * ins_text = NULL; /* if invalid offset is specified, do nothing. */ /* this fix is for aixim for eucTW */ if (cur_len < chg_1st) return; if(is_text_available(text)) { /* insert or replace the text */ if (text->encoding_is_wchar == False) { /* convert the text to wide chars. allocate enough size buffer */ tempbuf = (wchar_t *)malloc(sizeof(wchar_t)*(text->length+1)); if (tempbuf == NULL) { THROW_OUT_OF_MEMORY_ERROR(); return; } ins_len = (int32_t)mbstowcs(tempbuf, text->string.multi_byte, text->length); if (ins_len == -1) { free(tempbuf); return; } ins_text = (void *)tempbuf; } else { ins_len = text->length; ins_text = text->string.wide_char; } /* finish prepare the data to be inserted */ statusWindow->peText = handle_buffer(cur_text, ins_text, sizeof(wchar_t), cur_len, ins_len, chg_len, chg_1st); statusWindow->peAttr = handle_buffer(cur_attr, text->feedback, sizeof(long), cur_len, ins_len, chg_len, chg_1st); statusWindow->peText[cur_len-chg_len+ins_len] =L'\0'; if (tempbuf != NULL) free(tempbuf); } /* endof insert or replace text */ else { /* change attribute only */ memcpy(&cur_attr[chg_1st], text->feedback, sizeof(long)*text->length); } } statusWindow->peCaret= pre_draw->caret; draw_preedit(statusWindow); if (statusWindow->on && wcslen(statusWindow->peText) > 0) onoffStatusWindow(pX11IMData, statusWindow->parent, True); else if (wcslen(statusWindow->status) == 0) onoffStatusWindow(pX11IMData, 0, False); } /* * reset predit test of passive mode */ static void resetPassivePreeditText(StatusWindow *statusWindow) { if (NULL == statusWindow) return; if(statusWindow->peText != NULL) { free(statusWindow->peText); statusWindow->peText = NULL; } if(statusWindow->peAttr != NULL) { free(statusWindow->peAttr); statusWindow->peAttr = NULL; } statusWindow->peCaret= 0; } static void draw_caret(StatusWindow *statusWindow, GC gc, int pos) { if (NULL == statusWindow) return; XSetFunction(dpy, gc, GXinvert); XDrawLine(dpy, statusWindow->w, gc, pos, STATUS_BORDER/2, pos, STATUS_BORDER/2+statusWindow->fOff); XSetFunction(dpy, gc, GXcopy); } static int get_next_attr(int len, unsigned long *attr) { int count; for (count = 1; count < len; count++) { if ((attr[count-1] & PREEDIT_ATTR_MASK) != (attr[count] & PREEDIT_ATTR_MASK)) break; } return count; } static void draw_preedit(StatusWindow *statusWindow) { unsigned long *attr; int x_pos,x_caret; unsigned int len; int len_disp, pos; wchar_t *str; GC gc; XRectangle ink, rect, rect_c; Bool caret_done = False; if (NULL == statusWindow) return; align_status(statusWindow); XFillRectangle(dpy, statusWindow->w, statusWindow->bgGC, statusWindow->statusW,0, statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, statusWindow->fBot+2); XDrawLine(dpy, statusWindow->w, statusWindow->fgGC, statusWindow->statusW, 0, statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 0); XDrawLine(dpy, statusWindow->w, statusWindow->fgGC, statusWindow->statusW, statusWindow->fBot+2, statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, statusWindow->fBot+2); XDrawLine(dpy, statusWindow->w, statusWindow->fgGC, statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 0, statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, statusWindow->fBot+2); if (0 == statusWindow->statusW) XDrawLine(dpy, statusWindow->w, statusWindow->fgGC, 0, 0, 0, statusWindow->fBot+2); str = statusWindow->peText; if (str != NULL && (len = (int32_t)wcslen(str)) != 0) { pos = 0; attr = statusWindow->peAttr; x_pos = x_caret = statusWindow->statusW + STATUS_BORDER; while((int)len-1 >= pos) { len_disp = get_next_attr(len - pos, &attr[pos]); if (attr[pos] & XIMReverse) { gc = statusWindow->bgGC; } else { gc = statusWindow->fgGC; } XwcTextExtents(statusWindow->fontset, &str[pos], len_disp, &ink, &rect); XwcDrawImageString(dpy, statusWindow->w, statusWindow->fontset, gc, x_pos, statusWindow->fOff+1, &str[pos], len_disp); if (attr[pos] & XIMUnderline) { XDrawLine(dpy, statusWindow->w, gc, x_pos, statusWindow->fBot, x_pos+rect.width, statusWindow->fBot); } if (!caret_done) { if( statusWindow->peCaret >= pos && statusWindow->peCaret <= pos+len_disp) { if (statusWindow->peCaret == 0) x_caret = x_pos; else if (statusWindow->peCaret == pos+len_disp) x_caret = x_pos+rect.width; else { XwcTextExtents(statusWindow->fontset, &str[pos], statusWindow->peCaret-pos, &ink, &rect_c); x_caret = x_pos+ rect_c.width; } x_caret-=CARET_OFFSET; caret_done = True; } } pos += len_disp; x_pos += rect.width; } if (caret_done) draw_caret(statusWindow, statusWindow->fgGC, x_caret); } } /* calc requied status window size and resize the window */ static void align_status(StatusWindow *statusWindow) { int len_st, len_pe = 0; XRectangle rect_st, rect_pe, ink; Dimension cur_w; int value_make = CWX|CWWidth|CWHeight; XWindowChanges xwc; if (NULL == statusWindow) return; if ((len_st = st_wcslen(statusWindow->status)) == 0 && (statusWindow->peText == NULL || st_wcslen(statusWindow->peText) == 0 )) return; rect_pe.x = rect_pe.y = rect_pe.width = rect_pe.height = 0; XwcTextExtents(statusWindow->fontset, statusWindow->status, len_st, &ink, &rect_st); if (statusWindow->peText != NULL && (len_pe = (int32_t)wcslen(statusWindow->peText)) > 0) { XwcTextExtents(statusWindow->fontset, statusWindow->peText, len_pe, &ink, &rect_pe); } statusWindow->fOff = max(-rect_st.y, -rect_pe.y); statusWindow->fBot = max(rect_st.height, rect_pe.height); statusWindow->statusW =rect_st.width; if (rect_st.width > 0) statusWindow->statusW += BORDER_MARGIN; statusWindow->peTextW = rect_pe.width; xwc.x = statusWindow->x - statusWindow->off_x; if (xwc.x < 0 ) xwc.x = 0; if (len_pe > 0) { xwc.width = statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN + 1; xwc.height = statusWindow->fBot + BORDER_MARGIN; } else { xwc.width = statusWindow->statusW; xwc.height = statusWindow->fBot + BORDER_MARGIN; } if (xwc.x + xwc.width > statusWindow->rootW){ xwc.x = statusWindow->rootW - xwc.width; } XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); } static void shrink_status(StatusWindow *statusWindow) { int value_make = CWX|CWWidth|CWHeight; XWindowChanges xwc; if (NULL == statusWindow) return; xwc.width = statusWindow->statusW; xwc.height = statusWindow->statusH; statusWindow->peTextW = 0; xwc.x = statusWindow->x - statusWindow->off_x; if (xwc.x < 0 ) xwc.x = 0; if (xwc.x + xwc.width > statusWindow->rootW){ xwc.x = statusWindow->rootW - xwc.width; } XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); } static GC create_gc(Window win, Bool isReverse) { XGCValues xgcv; unsigned long mask; AwtScreenDataPtr defaultScreen; defaultScreen = getScreenData(DefaultScreen(dpy)); mask = (GCForeground | GCBackground ); if (isReverse) { xgcv.foreground = defaultScreen->whitepixel; xgcv.background = defaultScreen->blackpixel; } else { xgcv.foreground = defaultScreen->blackpixel; xgcv.background = defaultScreen->whitepixel; } return XCreateGC(dpy, win, mask, &xgcv); } static Bool isNativeIm() { #define XIMMODIFIER "@im=" #define XIM_SERVER_CATEGORY "@server=" char *immodifiers; char *imserver, *imserverPtr; Atom imserverAtom; if (!(immodifiers = getenv("XMODIFIERS"))) return True; if (!(imserver = calloc(1,strlen(immodifiers)+strlen(XIM_SERVER_CATEGORY)+1))) return True; if (!(immodifiers = strstr(immodifiers,XIMMODIFIER))) return True; immodifiers += strlen(XIMMODIFIER); strcpy(imserver,XIM_SERVER_CATEGORY); imserverPtr = imserver + strlen(imserver); while(*immodifiers != '@' && *immodifiers != '\0') { *imserverPtr = *immodifiers; imserverPtr++; immodifiers++; } imserverAtom = XInternAtom(awt_display, imserver, True); free(imserver); if (imserverAtom > 0) return False; else return True; } static Window getGrandParent(Window parent) { Window containerWindow,rootWindow,tmp; Window *ignoreWindowPtr; unsigned int ignoreUnit; Window grandParent=0; XWindowAttributes xwa; Atom WM_STATE; Atom type = None; int32_t format; unsigned long nitems, after; unsigned char * data; if (parent == 0) return grandParent; WM_STATE = XInternAtom(dpy, "WM_STATE", True); if (WM_STATE == None) return grandParent; tmp=parent; while(XQueryTree(dpy, tmp, &rootWindow, &containerWindow, &ignoreWindowPtr, &ignoreUnit)){ XFree(ignoreWindowPtr); if (containerWindow == rootWindow) break; if (XGetWindowProperty(dpy, containerWindow, WM_STATE, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &after, &data) == Success) { XFree(data); if (type) { XGetWindowAttributes(dpy, containerWindow, &xwa); if (FALSE == xwa.override_redirect){ grandParent=containerWindow; } } } tmp=containerWindow; } return grandParent; } static void moveStatusWindow(StatusWindow *statusWindow) { XWindowAttributes xwa; Window child; int x, y, width; Window target; if (NULL == statusWindow) return; if (statusWindow->grandParent){ target = statusWindow->grandParent; }else{ target = statusWindow->parent; } XGetWindowAttributes(dpy, target, &xwa); XTranslateCoordinates(dpy, target, xwa.root, 0, 0, &x, &y, &child); if (statusWindow->x != x || statusWindow->y != y || statusWindow->width != xwa.width || statusWindow->height != xwa.height){ statusWindow->x = x; statusWindow->y = y; statusWindow->height = xwa.height; statusWindow->width = xwa.width; x = statusWindow->x - statusWindow->off_x; y = statusWindow->y + statusWindow->height + statusWindow->off_y; if (x < 0 ){ x = 0; } if (statusWindow->peTextW > 0) { width = statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN + 1; if (x + width > statusWindow->rootW){ x = statusWindow->rootW - width; } } else { if (x + statusWindow->statusW > statusWindow->rootW){ x = statusWindow->rootW - statusWindow->statusW; } } if (y + statusWindow->statusH > statusWindow->rootH){ y = statusWindow->rootH - statusWindow->statusH; } XMoveWindow(dpy, statusWindow->w, x, y); } } static void arrange_window_stack(StatusWindow* statusWindow) { XWindowChanges xwc; int value_make = CWSibling|CWStackMode; Window root, parent, *children; unsigned int nchildren; if (NULL == statusWindow) return; if (XQueryTree(dpy, statusWindow->parent, &root, &parent, &children, &nchildren)){ XFree(children); xwc.sibling = parent; while(XQueryTree(dpy, xwc.sibling, &root, &parent, &children, &nchildren)) { XFree(children); if (root != parent) { xwc.sibling = parent; } else { break; } } xwc.stack_mode = Above; XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); } } static int count_missing_fonts(char **charset_list, int charset_count) { int i,j; if (charset_count > 0) { j=charset_count; for(i=0; i < charset_count; i++) { if ((strstr(charset_list[i], "IBM-udc")) || (strstr(charset_list[i], "IBM-sbd")) || (strstr(charset_list[i], "IBM-ucdTW"))) j--; } return j; } else return 0; } static XFontSet create_fontset_name(char * font_name, Bool force) { XFontSet fontset = NULL; char **charset_list; int charset_count; char *def_string; int missing_fonts; fontset = XCreateFontSet(dpy, font_name, &charset_list, &charset_count, &def_string); if (charset_count > 0) { missing_fonts = count_missing_fonts(charset_list, charset_count); XFreeStringList(charset_list); if (fontset && (missing_fonts > 0)) { if (!force) { XFreeFontSet(dpy, fontset); fontset = NULL; } } } return fontset; } static XFontSet create_fontset() { XFontSet fontset = NULL; int i; static char * fontlist[] = { "-dt-interface user-medium-r-normal-S*-*-*-*-*-*-*-*-*", "-*-*-medium-r-normal-*-14-*-*-*-c-*-*-*", "-*-*-medium-r-normal-*-14-*-*-*-m-*-*-*", "-*-*-medium-r-normal--14-0-0-0-m-*-*-*", "-monotype-sansmonowt-medium-r-normal--14-*-*-*-m-*-*-*", "-*--14-*", "-dt-interface user-medium-r-normal-s*-*-*-*-*-*-*-*-*", "-*--16-*", "-*--17-*", "-*--18-*", "-*--19-*", "-*--20-*", "-*--24-*", NULL}; for (i=0; fontlist[i] != NULL && fontset==NULL; i++) fontset = create_fontset_name(fontlist[i], False); if (!fontset) fprintf(stdout, "Cannot load fonts for IMF.\n"); return fontset; } static Window get_current_focus(XIC ic) { Window w = 0; if (ic != NULL) XGetICValues(ic, XNFocusWindow, &w, NULL); return w; } #endif