| /* |
| * Copyright (c) 1997, 2018, 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 "awt.h" |
| #include "awt_p.h" |
| |
| #include <sun_awt_X11InputMethodBase.h> |
| #include <sun_awt_X11InputMethod.h> |
| #include <sun_awt_X11_XInputMethod.h> |
| |
| #include <langinfo.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/time.h> |
| #include <wchar.h> |
| #include <wctype.h> |
| #include <X11/Intrinsic.h> |
| #include <X11/keysym.h> |
| #include <X11/Xlib.h> |
| |
| #define THROW_OUT_OF_MEMORY_ERROR() \ |
| JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL) |
| |
| struct X11InputMethodIDs { |
| jfieldID pData; |
| } x11InputMethodIDs; |
| |
| static int PreeditStartCallback(XIC, XPointer, XPointer); |
| static void PreeditDoneCallback(XIC, XPointer, XPointer); |
| static void PreeditDrawCallback(XIC, XPointer, |
| XIMPreeditDrawCallbackStruct *); |
| static void PreeditCaretCallback(XIC, XPointer, |
| XIMPreeditCaretCallbackStruct *); |
| static void StatusStartCallback(XIC, XPointer, XPointer); |
| static void StatusDoneCallback(XIC, XPointer, XPointer); |
| static void StatusDrawCallback(XIC, XPointer, |
| XIMStatusDrawCallbackStruct *); |
| |
| #define ROOT_WINDOW_STYLES (XIMPreeditNothing | XIMStatusNothing) |
| #define NO_STYLES (XIMPreeditNone | XIMStatusNone) |
| /* added style to allow for in-place composition, such as "dead" keys for accents */ |
| #define IN_PLACE_STYLES (XIMPreeditNothing | XIMStatusNone) |
| |
| #define PreeditStartIndex 0 |
| #define PreeditDoneIndex 1 |
| #define PreeditDrawIndex 2 |
| #define PreeditCaretIndex 3 |
| #define StatusStartIndex 4 |
| #define StatusDoneIndex 5 |
| #define StatusDrawIndex 6 |
| #define NCALLBACKS 7 |
| |
| #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 */ |
| |
| /* |
| * Callback function pointers: the order has to match the *Index |
| * values above. |
| */ |
| static XIMProc callback_funcs[NCALLBACKS] = { |
| (XIMProc)(void *)&PreeditStartCallback, |
| (XIMProc)PreeditDoneCallback, |
| (XIMProc)PreeditDrawCallback, |
| (XIMProc)PreeditCaretCallback, |
| (XIMProc)StatusStartCallback, |
| (XIMProc)StatusDoneCallback, |
| (XIMProc)StatusDrawCallback, |
| }; |
| |
| #define MAX_STATUS_LEN 100 |
| typedef struct { |
| Window w; /*status window id */ |
| Window root; /*the root window id */ |
| Window parent; /*parent shell window */ |
| Window grandParent; /*window has WM frame */ |
| 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 */ |
| wchar_t status[MAX_STATUS_LEN + 1]; /*status text */ |
| XFontSet fontset; /*fontset for drawing */ |
| int off_x, off_y; |
| Bool on; /*if the status window on*/ |
| 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 */ |
| } StatusWindow; |
| |
| /* |
| * 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 */ |
| StatusWindow *statusWindow; /* our own status window */ |
| Bool passiveStatusWindow;/* Passive Client uses StatusWindow */ |
| Bool isActiveClient; /* True:clinet is active */ |
| Bool forceReset; /* True: call resetXIC before UnsetICFocus */ |
| } X11InputMethodData; |
| |
| /* 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) |
| |
| static X11InputMethodData * getX11InputMethodData(JNIEnv *, jobject); |
| static void setX11InputMethodData(JNIEnv *, jobject, X11InputMethodData *); |
| static void destroyX11InputMethodData(JNIEnv *, X11InputMethodData *); |
| static void freeX11InputMethodData(JNIEnv *, X11InputMethodData *); |
| |
| /* Prototype for this function is missing in AIX Xlib.h */ |
| extern char *XSetIMValues( |
| #if NeedVarargsPrototypes |
| XIM /* im */, ... |
| #endif |
| ); |
| |
| 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); |
| |
| /* |
| * 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; |
| } |
| |
| 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); |
| /* 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 (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 (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; |
| } |
| free((void*)sw); |
| } |
| |
| if (pX11IMData->callbacks) |
| free((void *)pX11IMData->callbacks); |
| |
| if (env) { |
| (*env)->DeleteGlobalRef(env, pX11IMData->x11inputmethod); |
| } |
| |
| 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; |
| int buf_len = INITIAL_LOOKUP_BUF_SIZE; |
| char mbbuf[INITIAL_LOOKUP_BUF_SIZE]; |
| char *buf; |
| KeySym keysym = NoSymbol; |
| Status status; |
| int mblen; |
| jstring javastr; |
| XIC ic; |
| Boolean result = True; |
| static Boolean composing = False; |
| |
| /* |
| printf("lookupString: entering...\n"); |
| */ |
| |
| pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance); |
| |
| if (pX11IMData == NULL) { |
| return False; |
| } |
| |
| if ((ic = pX11IMData->current_ic) == (XIC)0){ |
| return False; |
| } |
| |
| buf = mbbuf; |
| mblen = XmbLookupString(ic, event, buf, |
| buf_len - 1, &keysym, &status); |
| |
| /* |
| * In case of overflow, a buffer is allocated and it retries |
| * XmbLookupString(). |
| */ |
| if (status == XBufferOverflow) { |
| 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); |
| } |
| buf[mblen] = 0; |
| |
| /* 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); |
| */ |
| javastr = JNU_NewStringPlatform(env, (const char *)buf); |
| if (javastr != NULL) { |
| JNU_CallMethodByName(env, NULL, |
| currentX11InputMethodInstance, |
| "dispatchCommittedText", |
| "(Ljava/lang/String;J)V", |
| javastr, |
| event->time); |
| if ((*env)->ExceptionOccurred(env)) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| } |
| } |
| 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 (buf != mbbuf) { |
| free(buf); |
| } |
| return result; |
| } |
| |
| 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; |
| Window grandParent; |
| Window target; |
| XFontSet fontset; |
| |
| fontset = create_fontset(); |
| if (NULL == fontset) { |
| return NULL; |
| } |
| |
| 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); |
| |
| grandParent = getGrandParent(parent); |
| target = (grandParent == 0) ? parent : grandParent; |
| XGetWindowAttributes(dpy, target, &xwa); |
| 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, |
| target, |
| &rootWindow, |
| &containerWindow, |
| &ignoreWindowPtr, |
| &ignoreUnit); |
| XGetWindowAttributes(dpy, containerWindow, &xxwa); |
| |
| 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); |
| } |
| } |
| |
| /*get the size of root window*/ |
| XGetWindowAttributes(dpy, rootWindow, &xxwa); |
| |
| XTranslateCoordinates(dpy, |
| target, xwa.root, |
| 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 ((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; |
| } |
| |
| 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 (grandParent != 0){ |
| long mask; |
| XGetWindowAttributes(dpy, grandParent, &xwa); |
| mask = xwa.your_event_mask | StructureNotifyMask | |
| VisibilityChangeMask | PropertyChangeMask; |
| XSelectInput(dpy, grandParent,mask); |
| } |
| |
| statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow)); |
| if (statusWindow == NULL){ |
| THROW_OUT_OF_MEMORY_ERROR(); |
| return NULL; |
| } |
| statusWindow->w = status; |
| statusWindow->fontset = fontset; |
| statusWindow->parent = parent; |
| statusWindow->grandParent = grandParent; |
| 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; |
| statusWindow->peTextW = 0; |
| 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); |
| statusWindow->fgGC = create_gc(status, FALSE); |
| XSetForeground(dpy, statusWindow->fgGC, fg); |
| statusWindow->bgGC = create_gc(status, TRUE); |
| XSetForeground(dpy, statusWindow->bgGC, bg); |
| statusWindow->status_ready = False; |
| wcscpy(statusWindow->status, L""); |
| 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 (NULL == pX11IMData || |
| NULL == (statusWindow = pX11IMData->statusWindow)){ |
| return; |
| } |
| |
| if (ON == False) { |
| XUnmapWindow(dpy, statusWindow->w); |
| return; |
| } |
| if (NULL == currentX11InputMethodInstance){ |
| return; |
| } |
| { |
| JNIEnv *env = GetJNIEnv(); |
| parent = JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, |
| "getCurrentParentWindow", |
| "()J").j; |
| if ((*env)->ExceptionOccurred(env)) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| } |
| } |
| if (statusWindow->parent != parent) { |
| statusWindow->parent = parent; |
| } |
| if (st_wcslen(statusWindow->status) > 0 || |
| (statusWindow->peText != NULL && st_wcslen(statusWindow->peText) > 0 )) { |
| moveStatusWindow(statusWindow); |
| XMapRaised(dpy, statusWindow->w); |
| } |
| } |
| |
| 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; |
| 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); |
| |
| 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); |
| |
| if (statusWindow->fontset) { |
| XwcDrawString(dpy, win, statusWindow->fontset, fggc, |
| -logical.x + 1, -logical.y + 1, |
| statusWindow->status, |
| st_wcslen(statusWindow->status)); |
| } 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]")); |
| } |
| } |
| |
| Bool statusWindowEventHandler(XEvent event) { |
| JNIEnv *env = GetJNIEnv(); |
| X11InputMethodData *pX11IMData = NULL; |
| StatusWindow *statusWindow; |
| |
| if (NULL == currentX11InputMethodInstance || |
| NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance)) || |
| NULL == (statusWindow = pX11IMData->statusWindow)) |
| { |
| return False; |
| } |
| |
| if (statusWindow->w == event.xany.window) { |
| switch (event.type) { |
| case Expose: |
| paintStatusWindow(statusWindow); |
| if (statusWindow->peText) |
| draw_preedit(statusWindow); |
| arrange_window_stack(statusWindow); |
| break; |
| case ConfigureNotify: |
| case VisibilityNotify: |
| arrange_window_stack(statusWindow); |
| break; |
| /* |
| case UnmapNotify: |
| case VisibilityNotify: |
| break; |
| */ |
| default: |
| break; |
| } |
| 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; |
| } |
| |
| static void adjustStatusWindow(Window shell) { |
| JNIEnv *env = GetJNIEnv(); |
| X11InputMethodData *pX11IMData = NULL; |
| StatusWindow *statusWindow; |
| |
| if (NULL == currentX11InputMethodInstance |
| || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance)) |
| || NULL == (statusWindow = pX11IMData->statusWindow) |
| || !statusWindow->on) |
| { |
| return; |
| } |
| |
| moveStatusWindow(statusWindow); |
| } |
| |
| /* |
| * 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, |
| in_place_styles = 0, |
| active_styles = 0, |
| passive_styles = 0, |
| no_styles = 0; |
| XIMCallback *callbacks; |
| unsigned short i; |
| XIMStyles *im_styles; |
| char *ret = NULL; |
| Bool passiveStatusWindow = False; |
| pX11IMData->statusWindow = NULL; |
| |
| if (X11im == NULL) { |
| return False; |
| } |
| if (!w) { |
| return False; |
| } |
| |
| if (getenv("IBMJAVA_PASSIVE") == NULL) { |
| passiveStatusWindow = False; |
| } else { |
| passiveStatusWindow = True; |
| } |
| |
| if (isNativeIm()) { passiveStatusWindow = True; } |
| |
| ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL); |
| |
| if (ret != NULL) { |
| jio_fprintf(stderr,"XGetIMValues: %s\n",ret); |
| return FALSE ; |
| } |
| |
| 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; |
| } |
| } |
| |
| 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]; |
| } |
| } |
| |
| XFree(im_styles); |
| |
| if (active_styles != on_the_spot_styles) { |
| if (passive_styles == ROOT_WINDOW_STYLES) |
| active_styles = passive_styles; |
| else { |
| if (in_place_styles == IN_PLACE_STYLES){ |
| active_styles = passive_styles = IN_PLACE_STYLES; |
| } else { |
| if (no_styles == NO_STYLES) |
| active_styles = passive_styles = NO_STYLES; |
| else |
| active_styles = passive_styles = 0; |
| } |
| } |
| } else { |
| if (!passiveStatusWindow) { |
| if (passive_styles != ROOT_WINDOW_STYLES) { |
| if (no_styles == NO_STYLES) |
| active_styles = passive_styles = NO_STYLES; |
| else |
| active_styles = passive_styles = 0; |
| } |
| } else |
| passive_styles = active_styles; |
| } |
| |
| if (active_styles == on_the_spot_styles) { |
| 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; |
| /*always try XIMStatusCallbacks for active client...*/ |
| { |
| if (on_the_spot_styles & XIMStatusCallbacks) { |
| status = (XVaNestedList)XVaCreateNestedList(0, |
| XNStatusStartCallback, &callbacks[StatusStartIndex], |
| XNStatusDoneCallback, &callbacks[StatusDoneIndex], |
| XNStatusDrawCallback, &callbacks[StatusDrawIndex], |
| NULL); |
| |
| if (status == NULL) |
| goto err; |
| } |
| pX11IMData->statusWindow = createStatusWindow(w); |
| pX11IMData->ic_active = XCreateIC(X11im, |
| XNClientWindow, w, |
| XNFocusWindow, w, |
| XNInputStyle, active_styles, |
| XNPreeditAttributes, preedit, |
| XNStatusAttributes, status, |
| NULL); |
| if (NULL != pX11IMData->statusWindow) { |
| pX11IMData->statusWindow->status_ready = True; |
| } |
| XFree((void *)status); |
| XFree((void *)preedit); |
| } |
| if (passiveStatusWindow) { |
| pX11IMData->ic_passive = pX11IMData->ic_active; |
| } else { |
| pX11IMData->ic_passive = XCreateIC(X11im, |
| XNClientWindow, w, |
| XNFocusWindow, w, |
| XNInputStyle, passive_styles, |
| NULL); |
| } |
| } else { |
| pX11IMData->ic_active = XCreateIC(X11im, |
| XNClientWindow, w, |
| XNFocusWindow, w, |
| XNInputStyle, active_styles, |
| NULL); |
| pX11IMData->ic_passive = pX11IMData->ic_active; |
| } |
| |
| // 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; |
| |
| if (pX11IMData->ic_active == (XIC)0 |
| || pX11IMData->ic_passive == (XIC)0) { |
| return False; |
| } |
| |
| /* Unset focus to avoid unexpected IM on */ |
| setXICFocus(pX11IMData->ic_active, False); |
| if (pX11IMData->ic_active != pX11IMData->ic_passive) |
| setXICFocus(pX11IMData->ic_passive, False); |
| |
| return True; |
| |
| err: |
| if (preedit) |
| XFree((void *)preedit); |
| THROW_OUT_OF_MEMORY_ERROR(); |
| return False; |
| } |
| |
| static int |
| PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data) |
| { |
| JNIEnv *env = GetJNIEnv(); |
| X11InputMethodData *pX11IMData; |
| |
| pX11IMData = getX11InputMethodData(env, (jobject)client_data); |
| if (pX11IMData == NULL || pX11IMData->statusWindow == NULL) { |
| return 0; |
| } |
| resetPassivePreeditText(pX11IMData->statusWindow); |
| |
| return -1; /* unlimited length for preedit text */ |
| } |
| |
| static void |
| PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data) |
| { |
| JNIEnv *env = GetJNIEnv(); |
| X11InputMethodData *pX11IMData; |
| |
| 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); |
| } |
| } |
| } |
| |
| /* |
| * 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 ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) { |
| goto finally; |
| } |
| |
| if (!pX11IMData->isActiveClient){ |
| if (ic == pX11IMData->ic_passive) { |
| preedit_draw_passive(pX11IMData, pre_draw); |
| } |
| goto finally; |
| } |
| |
| if ((text = pre_draw->text) != NULL) { |
| if (is_text_available(text)) { |
| 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 (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); |
| free(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 ((*env)->ExceptionOccurred(env)) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| } |
| |
| finally: |
| AWT_UNLOCK(); |
| return; |
| } |
| |
| static void |
| PreeditCaretCallback(XIC ic, XPointer client_data, |
| XIMPreeditCaretCallbackStruct *pre_caret) |
| { |
| XIMPreeditDrawCallbackStruct pre_draw; |
| |
| 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); |
| } |
| } |
| |
| 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; |
| int value_make = CWX|CWWidth|CWHeight; |
| XRectangle logical, ink; |
| XWindowChanges xwc; |
| int len; |
| |
| AWT_LOCK(); |
| |
| if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data)) |
| || NULL == (statusWindow = pX11IMData->statusWindow)){ |
| goto finally; |
| } |
| |
| if (status_draw->type == XIMTextType) { |
| XIMText *text = (status_draw->data).text; |
| if (text != NULL) { |
| if (text->string.multi_byte != NULL) { |
| 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); |
| } 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); |
| } |
| 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); |
| } |
| else { |
| wcscpy(statusWindow->status, L""); |
| /*just turnoff the status window |
| paintStatusWindow(statusWindow); |
| */ |
| onoffStatusWindow(pX11IMData, 0, False); |
| } |
| } |
| |
| finally: |
| AWT_UNLOCK(); |
| } |
| |
| /* 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 required 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; |
| } |
| |
| 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); |
| |
| if (X11im == NULL) { |
| X11im = XOpenIM(dpy, NULL, NULL, NULL); |
| } |
| |
| 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; |
| pX11IMData->statusWindow = NULL; |
| |
| setX11InputMethodData(env, this, pX11IMData); |
| |
| if (createXIC(env, pX11IMData, (Window)window) == False) { |
| destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData); |
| pX11IMData = (X11InputMethodData *) NULL; |
| setX11InputMethodData(env, this, pX11IMData); |
| if ((*env)->ExceptionCheck(env)) { |
| goto finally; |
| } |
| } |
| |
| 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; |
| } |
| pX11IMData->isActiveClient = active; |
| pX11IMData->current_ic = active ? |
| pX11IMData->ic_active : pX11IMData->ic_passive; |
| /* |
| * On Solaris2.6, setXICWindowFocus() has to be invoked |
| * before setting focus. |
| */ |
| get_current_focus(pX11IMData->current_ic); /* workaround for kinput2 and SCIM */ |
| if (currentFocusWindow != w) { |
| setXICWindowFocus(pX11IMData->current_ic, w); |
| setXICFocus(pX11IMData->current_ic, req); |
| currentX11InputMethodInstance = pX11IMData->x11inputmethod; |
| currentFocusWindow = w; |
| } else { |
| setXICFocus(pX11IMData->current_ic, req); |
| } |
| if ((active || pX11IMData->passiveStatusWindow) |
| && (pX11IMData->statusWindow && pX11IMData->statusWindow->on)) |
| onoffStatusWindow(pX11IMData, w, True); |
| } else { |
| currentX11InputMethodInstance = NULL; |
| currentFocusWindow = 0; |
| onoffStatusWindow(pX11IMData, 0, False); |
| if (pX11IMData->current_ic != NULL) |
| setXICFocus(pX11IMData->current_ic, req); |
| |
| pX11IMData->current_ic = (XIC)0; |
| } |
| |
| XFlush(dpy); |
| AWT_UNLOCK(); |
| } |
| |
| /* |
| * Class: sun_awt_X11InputMethodBase |
| * 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_X11InputMethodBase_initIDs |
| (JNIEnv *env, jclass cls) |
| { |
| x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"); |
| } |
| |
| /* |
| * Class: sun_awt_X11InputMethodBase |
| * Method: turnoffStatusWindow |
| * Signature: ()V |
| */ |
| JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_turnoffStatusWindow |
| (JNIEnv *env, jobject this) |
| { |
| X11InputMethodData *pX11IMData; |
| StatusWindow *statusWindow; |
| |
| AWT_LOCK(); |
| |
| if (NULL == currentX11InputMethodInstance |
| || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance)) |
| || NULL == (statusWindow = pX11IMData->statusWindow) |
| || !statusWindow->on ){ |
| AWT_UNLOCK(); |
| return; |
| } |
| onoffStatusWindow(pX11IMData, 0, False); |
| statusWindow->on = False; |
| |
| AWT_UNLOCK(); |
| } |
| |
| /* |
| * Class: sun_awt_X11InputMethodBase |
| * Method: disposeXIC |
| * Signature: ()V |
| */ |
| JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_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(); |
| } |
| |
| /* |
| * Class: sun_awt_X11InputMethodBase |
| * Method: resetXIC |
| * Signature: ()Ljava/lang/String; |
| */ |
| JNIEXPORT jstring JNICALL Java_sun_awt_X11InputMethodBase_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 (!isPreeditStateActive(pX11IMData->current_ic)) { |
| xText = NULL; |
| } else { |
| if (!(pX11IMData->forceReset)) |
| setXICFocus(pX11IMData->current_ic, FALSE); |
| xText = XmbResetIC(pX11IMData->current_ic); |
| if (!(pX11IMData->forceReset)) |
| setXICFocus(pX11IMData->current_ic, TRUE); |
| } |
| } else { |
| /* |
| * If there is no reference to the current XIC, try to reset both XICs. |
| */ |
| if (!isPreeditStateActive(pX11IMData->ic_active)) |
| xText = NULL; |
| else |
| 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) { |
| char *tmpText; |
| if (!isPreeditStateActive(pX11IMData->ic_passive)) |
| tmpText = NULL; |
| else |
| tmpText = XmbResetIC(pX11IMData->ic_passive); |
| 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); |
| } |
| |
| /* 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); |
| } |
| } |
| |
| AWT_UNLOCK(); |
| return jText; |
| } |
| |
| /* |
| * Class: sun_awt_X11InputMethodBase |
| * Method: setCompositionEnabledNative |
| * Signature: (Z)Z |
| * |
| * 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_X11InputMethodBase_setCompositionEnabledNative |
| (JNIEnv *env, jobject this, jboolean enable) |
| { |
| X11InputMethodData *pX11IMData; |
| char * ret = NULL; |
| XVaNestedList pr_atrb; |
| |
| AWT_LOCK(); |
| pX11IMData = getX11InputMethodData(env, this); |
| |
| if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { |
| AWT_UNLOCK(); |
| return JNI_FALSE; |
| } |
| |
| 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", ""); |
| } |
| |
| return (jboolean)(ret == 0); |
| } |
| |
| /* |
| * Class: sun_awt_X11InputMethodBase |
| * Method: isCompositionEnabledNative |
| * Signature: ()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_X11InputMethodBase_isCompositionEnabledNative |
| (JNIEnv *env, jobject this) |
| { |
| X11InputMethodData *pX11IMData = NULL; |
| char * ret = NULL; |
| XIMPreeditState state = XIMPreeditUnKnown; |
| XVaNestedList pr_atrb; |
| |
| AWT_LOCK(); |
| pX11IMData = getX11InputMethodData(env, this); |
| |
| if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { |
| AWT_UNLOCK(); |
| return JNI_FALSE; |
| } |
| |
| 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; |
| } |
| |
| return (jboolean)(state == XIMPreeditEnable); |
| } |
| |
| JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow |
| (JNIEnv *env, jobject this, jlong window) |
| { |
| |
| } |
| |
| /* |
| * Class: sun_awt_X11InputMethod |
| * Method: setStatusAreaVisible |
| * Signature: (ZJ)V |
| */ |
| 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; |
| } |