1 /*
   2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #ifdef HEADLESS
  27     #error This file should not be included in headless library
  28 #endif
  29 
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <X11/Xlib.h>
  33 #include <sys/time.h>
  34 
  35 #include "awt.h"
  36 #include "awt_p.h"
  37 
  38 #include <sun_awt_X11InputMethod.h>
  39 #include <sun_awt_X11_XInputMethod.h>
  40 
  41 #define THROW_OUT_OF_MEMORY_ERROR() \
  42         JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL)
  43 #define SETARG(name, value)     XtSetArg(args[argc], name, value); argc++
  44 
  45 struct X11InputMethodIDs {
  46   jfieldID pData;
  47 } x11InputMethodIDs;
  48 
  49 static void PreeditStartCallback(XIC, XPointer, XPointer);
  50 static void PreeditDoneCallback(XIC, XPointer, XPointer);
  51 static void PreeditDrawCallback(XIC, XPointer,
  52                                 XIMPreeditDrawCallbackStruct *);
  53 static void PreeditCaretCallback(XIC, XPointer,
  54                                  XIMPreeditCaretCallbackStruct *);
  55 #if defined(__linux__) || defined(MACOSX)
  56 static void StatusStartCallback(XIC, XPointer, XPointer);
  57 static void StatusDoneCallback(XIC, XPointer, XPointer);
  58 static void StatusDrawCallback(XIC, XPointer,
  59                                XIMStatusDrawCallbackStruct *);
  60 #endif
  61 
  62 #define ROOT_WINDOW_STYLES      (XIMPreeditNothing | XIMStatusNothing)
  63 #define NO_STYLES               (XIMPreeditNone | XIMStatusNone)
  64 
  65 #define PreeditStartIndex       0
  66 #define PreeditDoneIndex        1
  67 #define PreeditDrawIndex        2
  68 #define PreeditCaretIndex       3
  69 #if defined(__linux__) || defined(MACOSX)
  70 #define StatusStartIndex        4
  71 #define StatusDoneIndex         5
  72 #define StatusDrawIndex         6
  73 #define NCALLBACKS              7
  74 #else
  75 #define NCALLBACKS              4
  76 #endif
  77 
  78 /*
  79  * Callback function pointers: the order has to match the *Index
  80  * values above.
  81  */
  82 static XIMProc callback_funcs[NCALLBACKS] = {
  83     (XIMProc)PreeditStartCallback,
  84     (XIMProc)PreeditDoneCallback,
  85     (XIMProc)PreeditDrawCallback,
  86     (XIMProc)PreeditCaretCallback,
  87 #if defined(__linux__) || defined(MACOSX)
  88     (XIMProc)StatusStartCallback,
  89     (XIMProc)StatusDoneCallback,
  90     (XIMProc)StatusDrawCallback,
  91 #endif
  92 };
  93 
  94 #if defined(__linux__) || defined(MACOSX)
  95 #define MAX_STATUS_LEN  100
  96 typedef struct {
  97     Window   w;                /*status window id        */
  98     Window   root;             /*the root window id      */
  99     Window   parent;           /*parent shell window     */
 100     int      x, y;             /*parent's upperleft position */
 101     int      width, height;    /*parent's width, height  */
 102     GC       lightGC;          /*gc for light border     */
 103     GC       dimGC;            /*gc for dim border       */
 104     GC       bgGC;             /*normal painting         */
 105     GC       fgGC;             /*normal painting         */
 106     int      statusW, statusH; /*status window's w, h    */
 107     int      rootW, rootH;     /*root window's w, h    */
 108     int      bWidth;           /*border width            */
 109     char     status[MAX_STATUS_LEN]; /*status text       */
 110     XFontSet fontset;           /*fontset for drawing    */
 111     int      off_x, off_y;
 112     Bool     on;                /*if the status window on*/
 113 } StatusWindow;
 114 #endif
 115 
 116 /*
 117  * X11InputMethodData keeps per X11InputMethod instance information. A pointer
 118  * to this data structure is kept in an X11InputMethod object (pData).
 119  */
 120 typedef struct _X11InputMethodData {
 121     XIC         current_ic;     /* current X Input Context */
 122     XIC         ic_active;      /* X Input Context for active clients */
 123     XIC         ic_passive;     /* X Input Context for passive clients */
 124     XIMCallback *callbacks;     /* callback parameters */
 125     jobject     x11inputmethod; /* global ref to X11InputMethod instance */
 126                                 /* associated with the XIC */
 127 #if defined(__linux__) || defined(MACOSX)
 128     StatusWindow *statusWindow; /* our own status window  */
 129 #endif
 130     char        *lookup_buf;    /* buffer used for XmbLookupString */
 131     int         lookup_buf_len; /* lookup buffer size in bytes */
 132 } X11InputMethodData;
 133 
 134 /*
 135  * When XIC is created, a global reference is created for
 136  * sun.awt.X11InputMethod object so that it could be used by the XIM callback
 137  * functions. This could be a dangerous thing to do when the original
 138  * X11InputMethod object is garbage collected and as a result,
 139  * destroyX11InputMethodData is called to delete the global reference.
 140  * If any XIM callback function still holds and uses the "already deleted"
 141  * global reference, disaster is going to happen. So we have to maintain
 142  * a list for these global references which is consulted first when the
 143  * callback functions or any function tries to use "currentX11InputMethodObject"
 144  * which always refers to the global reference try to use it.
 145  *
 146  */
 147 typedef struct _X11InputMethodGRefNode {
 148     jobject inputMethodGRef;
 149     struct _X11InputMethodGRefNode* next;
 150 } X11InputMethodGRefNode;
 151 
 152 X11InputMethodGRefNode *x11InputMethodGRefListHead = NULL;
 153 
 154 /* reference to the current X11InputMethod instance, it is always
 155    point to the global reference to the X11InputMethodObject since
 156    it could be referenced by different threads. */
 157 jobject currentX11InputMethodInstance = NULL;
 158 
 159 Window  currentFocusWindow = 0;  /* current window that has focus for input
 160                                        method. (the best place to put this
 161                                        information should be
 162                                        currentX11InputMethodInstance's pData) */
 163 static XIM X11im = NULL;
 164 Display * dpy = NULL;
 165 
 166 #define GetJNIEnv() (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2)
 167 
 168 static void DestroyXIMCallback(XIM, XPointer, XPointer);
 169 static void OpenXIMCallback(Display *, XPointer, XPointer);
 170 /* Solaris XIM Extention */
 171 #define XNCommitStringCallback "commitStringCallback"
 172 static void CommitStringCallback(XIC, XPointer, XPointer);
 173 
 174 static X11InputMethodData * getX11InputMethodData(JNIEnv *, jobject);
 175 static void setX11InputMethodData(JNIEnv *, jobject, X11InputMethodData *);
 176 static void destroyX11InputMethodData(JNIEnv *, X11InputMethodData *);
 177 static void freeX11InputMethodData(JNIEnv *, X11InputMethodData *);
 178 
 179 #ifdef __solaris__
 180 /* Prototype for this function is missing in Solaris X11R6 Xlib.h */
 181 extern char *XSetIMValues(
 182 #if NeedVarargsPrototypes
 183     XIM /* im */, ...
 184 #endif
 185 );
 186 #endif
 187 
 188 /*
 189  * This function is stolen from /src/solaris/hpi/src/system_md.c
 190  * It is used in setting the time in Java-level InputEvents
 191  */
 192 jlong
 193 awt_util_nowMillisUTC()
 194 {
 195     struct timeval t;
 196     gettimeofday(&t, NULL);
 197     return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000);
 198 }
 199 
 200 /*
 201  * Converts the wchar_t string to a multi-byte string calling wcstombs(). A
 202  * buffer is allocated by malloc() to store the multi-byte string. NULL is
 203  * returned if the given wchar_t string pointer is NULL or buffer allocation is
 204  * failed.
 205  */
 206 static char *
 207 wcstombsdmp(wchar_t *wcs, int len)
 208 {
 209     size_t n;
 210     char *mbs;
 211 
 212     if (wcs == NULL)
 213         return NULL;
 214 
 215     n = len*MB_CUR_MAX + 1;
 216 
 217     mbs = (char *) malloc(n * sizeof(char));
 218     if (mbs == NULL) {
 219         THROW_OUT_OF_MEMORY_ERROR();
 220         return NULL;
 221     }
 222 
 223     /* TODO: check return values... Handle invalid characters properly...  */
 224     if (wcstombs(mbs, wcs, n) == (size_t)-1)
 225         return NULL;
 226 
 227     return mbs;
 228 }
 229 
 230 /*
 231  * Returns True if the global reference is still in the list,
 232  * otherwise False.
 233  */
 234 static Bool isX11InputMethodGRefInList(jobject imGRef) {
 235     X11InputMethodGRefNode *pX11InputMethodGRef = x11InputMethodGRefListHead;
 236 
 237     if (imGRef == NULL) {
 238         return False;
 239     }
 240 
 241     while (pX11InputMethodGRef != NULL) {
 242         if (pX11InputMethodGRef->inputMethodGRef == imGRef) {
 243             return True;
 244         }
 245         pX11InputMethodGRef = pX11InputMethodGRef->next;
 246     }
 247 
 248     return False;
 249 }
 250 
 251 /*
 252  * Add the new created global reference to the list.
 253  */
 254 static void addToX11InputMethodGRefList(jobject newX11InputMethodGRef) {
 255     X11InputMethodGRefNode *newNode = NULL;
 256 
 257     if (newX11InputMethodGRef == NULL ||
 258         isX11InputMethodGRefInList(newX11InputMethodGRef)) {
 259         return;
 260     }
 261 
 262     newNode = (X11InputMethodGRefNode *)malloc(sizeof(X11InputMethodGRefNode));
 263 
 264     if (newNode == NULL) {
 265         return;
 266     } else {
 267         newNode->inputMethodGRef = newX11InputMethodGRef;
 268         newNode->next = x11InputMethodGRefListHead;
 269         x11InputMethodGRefListHead = newNode;
 270     }
 271 }
 272 
 273 /*
 274  * Remove the global reference from the list.
 275  */
 276 static void removeX11InputMethodGRefFromList(jobject x11InputMethodGRef) {
 277      X11InputMethodGRefNode *pX11InputMethodGRef = NULL;
 278      X11InputMethodGRefNode *cX11InputMethodGRef = x11InputMethodGRefListHead;
 279 
 280      if (x11InputMethodGRefListHead == NULL ||
 281          x11InputMethodGRef == NULL) {
 282          return;
 283      }
 284 
 285      /* cX11InputMethodGRef always refers to the current node while
 286         pX11InputMethodGRef refers to the previous node.
 287      */
 288      while (cX11InputMethodGRef != NULL) {
 289          if (cX11InputMethodGRef->inputMethodGRef == x11InputMethodGRef) {
 290              break;
 291          }
 292          pX11InputMethodGRef = cX11InputMethodGRef;
 293          cX11InputMethodGRef = cX11InputMethodGRef->next;
 294      }
 295 
 296      if (cX11InputMethodGRef == NULL) {
 297          return; /* Not found. */
 298      }
 299 
 300      if (cX11InputMethodGRef == x11InputMethodGRefListHead) {
 301          x11InputMethodGRefListHead = x11InputMethodGRefListHead->next;
 302      } else {
 303          pX11InputMethodGRef->next = cX11InputMethodGRef->next;
 304      }
 305      free(cX11InputMethodGRef);
 306 
 307      return;
 308 }
 309 
 310 
 311 static X11InputMethodData * getX11InputMethodData(JNIEnv * env, jobject imInstance) {
 312     X11InputMethodData *pX11IMData =
 313         (X11InputMethodData *)JNU_GetLongFieldAsPtr(env, imInstance, x11InputMethodIDs.pData);
 314 
 315     /*
 316      * In case the XIM server was killed somehow, reset X11InputMethodData.
 317      */
 318     if (X11im == NULL && pX11IMData != NULL) {
 319         JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
 320                              "flushText",
 321                              "()V");
 322         /* IMPORTANT:
 323            The order of the following calls is critical since "imInstance" may
 324            point to the global reference itself, if "freeX11InputMethodData" is called
 325            first, the global reference will be destroyed and "setX11InputMethodData"
 326            will in fact fail silently. So pX11IMData will not be set to NULL.
 327            This could make the original java object refers to a deleted pX11IMData
 328            object.
 329         */
 330         setX11InputMethodData(env, imInstance, NULL);
 331         freeX11InputMethodData(env, pX11IMData);
 332         pX11IMData = NULL;
 333     }
 334 
 335     return pX11IMData;
 336 }
 337 
 338 static void setX11InputMethodData(JNIEnv * env, jobject imInstance, X11InputMethodData *pX11IMData) {
 339     JNU_SetLongFieldFromPtr(env, imInstance, x11InputMethodIDs.pData, pX11IMData);
 340 }
 341 
 342 /* this function should be called within AWT_LOCK() */
 343 static void
 344 destroyX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData)
 345 {
 346     /*
 347      * Destroy XICs
 348      */
 349     if (pX11IMData == NULL) {
 350         return;
 351     }
 352 
 353     if (pX11IMData->ic_active != (XIC)0) {
 354         XUnsetICFocus(pX11IMData->ic_active);
 355         XDestroyIC(pX11IMData->ic_active);
 356         if (pX11IMData->ic_active != pX11IMData->ic_passive) {
 357             if (pX11IMData->ic_passive != (XIC)0) {
 358                 XUnsetICFocus(pX11IMData->ic_passive);
 359                 XDestroyIC(pX11IMData->ic_passive);
 360             }
 361             pX11IMData->ic_passive = (XIC)0;
 362             pX11IMData->current_ic = (XIC)0;
 363         }
 364     }
 365 
 366     freeX11InputMethodData(env, pX11IMData);
 367 }
 368 
 369 static void
 370 freeX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData)
 371 {
 372 #if defined(__linux__) || defined(MACOSX)
 373     if (pX11IMData->statusWindow != NULL){
 374         StatusWindow *sw = pX11IMData->statusWindow;
 375         XFreeGC(awt_display, sw->lightGC);
 376         XFreeGC(awt_display, sw->dimGC);
 377         XFreeGC(awt_display, sw->bgGC);
 378         XFreeGC(awt_display, sw->fgGC);
 379         if (sw->fontset != NULL) {
 380             XFreeFontSet(awt_display, sw->fontset);
 381         }
 382         XDestroyWindow(awt_display, sw->w);
 383         free((void*)sw);
 384     }
 385 #endif
 386 
 387     if (pX11IMData->callbacks)
 388         free((void *)pX11IMData->callbacks);
 389 
 390     if (env) {
 391         /* Remove the global reference from the list, so that
 392            the callback function or whoever refers to it could know.
 393         */
 394         removeX11InputMethodGRefFromList(pX11IMData->x11inputmethod);
 395         (*env)->DeleteGlobalRef(env, pX11IMData->x11inputmethod);
 396     }
 397 
 398     if (pX11IMData->lookup_buf) {
 399         free((void *)pX11IMData->lookup_buf);
 400     }
 401 
 402     free((void *)pX11IMData);
 403 }
 404 
 405 /*
 406  * Sets or unsets the focus to the given XIC.
 407  */
 408 static void
 409 setXICFocus(XIC ic, unsigned short req)
 410 {
 411     if (ic == NULL) {
 412         (void)fprintf(stderr, "Couldn't find X Input Context\n");
 413         return;
 414     }
 415     if (req == 1)
 416         XSetICFocus(ic);
 417     else
 418         XUnsetICFocus(ic);
 419 }
 420 
 421 /*
 422  * Sets the focus window to the given XIC.
 423  */
 424 static void
 425 setXICWindowFocus(XIC ic, Window w)
 426 {
 427     if (ic == NULL) {
 428         (void)fprintf(stderr, "Couldn't find X Input Context\n");
 429         return;
 430     }
 431     (void) XSetICValues(ic, XNFocusWindow, w, NULL);
 432 }
 433 
 434 /*
 435  * Invokes XmbLookupString() to get something from the XIM. It invokes
 436  * X11InputMethod.dispatchCommittedText() if XmbLookupString() returns
 437  * committed text.  This function is called from handleKeyEvent in canvas.c and
 438  * it's under the Motif event loop thread context.
 439  *
 440  * Buffer usage: There is a bug in XFree86-4.3.0 XmbLookupString implementation,
 441  * where it never returns XBufferOverflow.  We need to allocate the initial lookup buffer
 442  * big enough, so that the possibility that user encounters this problem is relatively
 443  * small.  When this bug gets fixed, we can make the initial buffer size smaller.
 444  * Note that XmbLookupString() sometimes produces a non-null-terminated string.
 445  *
 446  * Returns True when there is a keysym value to be handled.
 447  */
 448 #define INITIAL_LOOKUP_BUF_SIZE 512
 449 
 450 Bool
 451 awt_x11inputmethod_lookupString(XKeyPressedEvent *event, KeySym *keysymp)
 452 {
 453     JNIEnv *env = GetJNIEnv();
 454     X11InputMethodData *pX11IMData = NULL;
 455     KeySym keysym = NoSymbol;
 456     Status status;
 457     int mblen;
 458     jstring javastr;
 459     XIC ic;
 460     Bool result = True;
 461     static Bool composing = False;
 462 
 463     /*
 464       printf("lookupString: entering...\n");
 465      */
 466 
 467     if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) {
 468         currentX11InputMethodInstance = NULL;
 469         return False;
 470     }
 471 
 472     pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
 473 
 474     if (pX11IMData == NULL) {
 475 #if defined(__linux__) || defined(MACOSX)
 476         return False;
 477 #else
 478         return result;
 479 #endif
 480     }
 481 
 482     if ((ic = pX11IMData->current_ic) == (XIC)0){
 483 #if defined(__linux__) || defined(MACOSX)
 484         return False;
 485 #else
 486         return result;
 487 #endif
 488     }
 489 
 490     /* allocate the lookup buffer at the first invocation */
 491     if (pX11IMData->lookup_buf_len == 0) {
 492         pX11IMData->lookup_buf = (char *)malloc(INITIAL_LOOKUP_BUF_SIZE);
 493         if (pX11IMData->lookup_buf == NULL) {
 494             THROW_OUT_OF_MEMORY_ERROR();
 495             return result;
 496         }
 497         pX11IMData->lookup_buf_len = INITIAL_LOOKUP_BUF_SIZE;
 498     }
 499 
 500     mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf,
 501                             pX11IMData->lookup_buf_len - 1, &keysym, &status);
 502 
 503     /*
 504      * In case of overflow, a buffer is allocated and it retries
 505      * XmbLookupString().
 506      */
 507     if (status == XBufferOverflow) {
 508         free((void *)pX11IMData->lookup_buf);
 509         pX11IMData->lookup_buf_len = 0;
 510         pX11IMData->lookup_buf = (char *)malloc(mblen + 1);
 511         if (pX11IMData->lookup_buf == NULL) {
 512             THROW_OUT_OF_MEMORY_ERROR();
 513             return result;
 514         }
 515         pX11IMData->lookup_buf_len = mblen + 1;
 516         mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf,
 517                             pX11IMData->lookup_buf_len - 1, &keysym, &status);
 518     }
 519     pX11IMData->lookup_buf[mblen] = 0;
 520 
 521     /* Get keysym without taking modifiers into account first to map
 522      * to AWT keyCode table.
 523      */
 524     switch (status) {
 525     case XLookupBoth:
 526         if (!composing) {
 527             if (event->keycode != 0) {
 528                 *keysymp = keysym;
 529                 result = False;
 530                 break;
 531             }
 532         }
 533         composing = False;
 534         /*FALLTHRU*/
 535     case XLookupChars:
 536     /*
 537      printf("lookupString: status=XLookupChars, type=%d, state=%x, keycode=%x, keysym=%x\n",
 538        event->type, event->state, event->keycode, keysym);
 539     */
 540         javastr = JNU_NewStringPlatform(env, (const char *)pX11IMData->lookup_buf);
 541         if (javastr != NULL) {
 542             JNU_CallMethodByName(env, NULL,
 543                                  currentX11InputMethodInstance,
 544                                  "dispatchCommittedText",
 545                                  "(Ljava/lang/String;J)V",
 546                                  javastr,
 547                                  event->time);
 548         }
 549         break;
 550 
 551     case XLookupKeySym:
 552     /*
 553      printf("lookupString: status=XLookupKeySym, type=%d, state=%x, keycode=%x, keysym=%x\n",
 554        event->type, event->state, event->keycode, keysym);
 555     */
 556         if (keysym == XK_Multi_key)
 557             composing = True;
 558         if (! composing) {
 559             *keysymp = keysym;
 560             result = False;
 561         }
 562         break;
 563 
 564     case XLookupNone:
 565     /*
 566      printf("lookupString: status=XLookupNone, type=%d, state=%x, keycode=%x, keysym=%x\n",
 567         event->type, event->state, event->keycode, keysym);
 568     */
 569         break;
 570     }
 571 
 572     return result;
 573 }
 574 
 575 #if defined(__linux__) || defined(MACOSX)
 576 static StatusWindow *createStatusWindow(
 577                                 Window parent) {
 578     StatusWindow *statusWindow;
 579     XSetWindowAttributes attrib;
 580     unsigned long attribmask;
 581     Window containerWindow;
 582     Window status;
 583     Window child;
 584     XWindowAttributes xwa;
 585     XWindowAttributes xxwa;
 586     /* Variable for XCreateFontSet()*/
 587     char **mclr;
 588     int  mccr = 0;
 589     char *dsr;
 590     Pixel bg, fg, light, dim;
 591     int x, y, off_x, off_y, xx, yy;
 592     unsigned int w, h, bw, depth;
 593     XGCValues values;
 594     unsigned long valuemask = 0;  /*ignore XGCvalue and use defaults*/
 595     int screen = 0;
 596     int i;
 597     AwtGraphicsConfigDataPtr adata;
 598     extern int awt_numScreens;
 599     /*hardcode the size right now, should get the size base on font*/
 600     int   width=80, height=22;
 601     Window rootWindow;
 602     Window *ignoreWindowPtr;
 603     unsigned int ignoreUnit;
 604 
 605     XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth);
 606 
 607     attrib.override_redirect = True;
 608     attribmask = CWOverrideRedirect;
 609     for (i = 0; i < awt_numScreens; i++) {
 610         if (RootWindow(dpy, i) == rootWindow) {
 611             screen = i;
 612             break;
 613         }
 614     }
 615     adata = getDefaultConfig(screen);
 616     bg    = adata->AwtColorMatch(255, 255, 255, adata);
 617     fg    = adata->AwtColorMatch(0, 0, 0, adata);
 618     light = adata->AwtColorMatch(195, 195, 195, adata);
 619     dim   = adata->AwtColorMatch(128, 128, 128, adata);
 620 
 621     XGetWindowAttributes(dpy, parent, &xwa);
 622     bw = 2; /*xwa.border_width does not have the correct value*/
 623 
 624     /*compare the size difference between parent container
 625       and shell widget, the diff should be the border frame
 626       and title bar height (?)*/
 627 
 628     XQueryTree( dpy,
 629                 parent,
 630                 &rootWindow,
 631                 &containerWindow,
 632                 &ignoreWindowPtr,
 633                 &ignoreUnit);
 634     XGetWindowAttributes(dpy, containerWindow, &xxwa);
 635 
 636     off_x = (xxwa.width - xwa.width) / 2;
 637     off_y = xxwa.height - xwa.height - off_x; /*it's magic:-) */
 638 
 639     /*get the size of root window*/
 640     XGetWindowAttributes(dpy, rootWindow, &xxwa);
 641 
 642     XTranslateCoordinates(dpy,
 643                           parent, xwa.root,
 644                           xwa.x, xwa.y,
 645                           &x, &y,
 646                           &child);
 647     xx = x - off_x;
 648     yy = y + xwa.height - off_y;
 649     if (xx < 0 ){
 650         xx = 0;
 651     }
 652     if (xx + width > xxwa.width){
 653         xx = xxwa.width - width;
 654     }
 655     if (yy + height > xxwa.height){
 656         yy = xxwa.height - height;
 657     }
 658 
 659     status =  XCreateWindow(dpy,
 660                             xwa.root,
 661                             xx, yy,
 662                             width, height,
 663                             0,
 664                             xwa.depth,
 665                             InputOutput,
 666                             adata->awt_visInfo.visual,
 667                             attribmask, &attrib);
 668     XSelectInput(dpy, status,
 669                  ExposureMask | StructureNotifyMask | EnterWindowMask |
 670                  LeaveWindowMask | VisibilityChangeMask);
 671     statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow));
 672     if (statusWindow == NULL){
 673         THROW_OUT_OF_MEMORY_ERROR();
 674         return NULL;
 675     }
 676     statusWindow->w = status;
 677     //12-point font
 678     statusWindow->fontset = XCreateFontSet(dpy,
 679                                            "-*-*-medium-r-normal-*-*-120-*-*-*-*",
 680                                            &mclr, &mccr, &dsr);
 681     /* In case we didn't find the font set, release the list of missing characters */
 682     if (mccr > 0) {
 683         XFreeStringList(mclr);
 684     }
 685     statusWindow->parent = parent;
 686     statusWindow->on  = False;
 687     statusWindow->x = x;
 688     statusWindow->y = y;
 689     statusWindow->width = xwa.width;
 690     statusWindow->height = xwa.height;
 691     statusWindow->off_x = off_x;
 692     statusWindow->off_y = off_y;
 693     statusWindow->bWidth  = bw;
 694     statusWindow->statusH = height;
 695     statusWindow->statusW = width;
 696     statusWindow->rootH = xxwa.height;
 697     statusWindow->rootW = xxwa.width;
 698     statusWindow->lightGC = XCreateGC(dpy, status, valuemask, &values);
 699     XSetForeground(dpy, statusWindow->lightGC, light);
 700     statusWindow->dimGC = XCreateGC(dpy, status, valuemask, &values);
 701     XSetForeground(dpy, statusWindow->dimGC, dim);
 702     statusWindow->fgGC = XCreateGC(dpy, status, valuemask, &values);
 703     XSetForeground(dpy, statusWindow->fgGC, fg);
 704     statusWindow->bgGC = XCreateGC(dpy, status, valuemask, &values);
 705     XSetForeground(dpy, statusWindow->bgGC, bg);
 706     return statusWindow;
 707 }
 708 
 709 /* This method is to turn off or turn on the status window. */
 710 static void onoffStatusWindow(X11InputMethodData* pX11IMData,
 711                                 Window parent,
 712                                 Bool ON){
 713     XWindowAttributes xwa;
 714     Window child;
 715     int x, y;
 716     StatusWindow *statusWindow = NULL;
 717 
 718     if (NULL == currentX11InputMethodInstance ||
 719         NULL == pX11IMData ||
 720         NULL == (statusWindow =  pX11IMData->statusWindow)){
 721         return;
 722     }
 723 
 724     if (ON == False){
 725         XUnmapWindow(dpy, statusWindow->w);
 726         statusWindow->on = False;
 727         return;
 728     }
 729     parent = JNU_CallMethodByName(GetJNIEnv(), NULL, pX11IMData->x11inputmethod,
 730                                   "getCurrentParentWindow",
 731                                   "()J").j;
 732     if (statusWindow->parent != parent){
 733         statusWindow->parent = parent;
 734     }
 735     XGetWindowAttributes(dpy, parent, &xwa);
 736     XTranslateCoordinates(dpy,
 737                           parent, xwa.root,
 738                           xwa.x, xwa.y,
 739                           &x, &y,
 740                           &child);
 741     if (statusWindow->x != x
 742         || statusWindow->y != y
 743         || statusWindow->height != xwa.height){
 744         statusWindow->x = x;
 745         statusWindow->y = y;
 746         statusWindow->height = xwa.height;
 747         x = statusWindow->x - statusWindow->off_x;
 748         y = statusWindow->y + statusWindow->height - statusWindow->off_y;
 749         if (x < 0 ){
 750             x = 0;
 751         }
 752         if (x + statusWindow->statusW > statusWindow->rootW){
 753             x = statusWindow->rootW - statusWindow->statusW;
 754         }
 755         if (y + statusWindow->statusH > statusWindow->rootH){
 756             y = statusWindow->rootH - statusWindow->statusH;
 757         }
 758         XMoveWindow(dpy, statusWindow->w, x, y);
 759     }
 760     statusWindow->on = True;
 761     XMapWindow(dpy, statusWindow->w);
 762 }
 763 
 764 void paintStatusWindow(StatusWindow *statusWindow){
 765     Window  win  = statusWindow->w;
 766     GC  lightgc = statusWindow->lightGC;
 767     GC  dimgc = statusWindow->dimGC;
 768     GC  bggc = statusWindow->bgGC;
 769     GC  fggc = statusWindow->fgGC;
 770 
 771     int width = statusWindow->statusW;
 772     int height = statusWindow->statusH;
 773     int bwidth = statusWindow->bWidth;
 774     XFillRectangle(dpy, win, bggc, 0, 0, width, height);
 775     /* draw border */
 776     XDrawLine(dpy, win, fggc, 0, 0, width, 0);
 777     XDrawLine(dpy, win, fggc, 0, height-1, width-1, height-1);
 778     XDrawLine(dpy, win, fggc, 0, 0, 0, height-1);
 779     XDrawLine(dpy, win, fggc, width-1, 0, width-1, height-1);
 780 
 781     XDrawLine(dpy, win, lightgc, 1, 1, width-bwidth, 1);
 782     XDrawLine(dpy, win, lightgc, 1, 1, 1, height-2);
 783     XDrawLine(dpy, win, lightgc, 1, height-2, width-bwidth, height-2);
 784     XDrawLine(dpy, win, lightgc, width-bwidth-1, 1, width-bwidth-1, height-2);
 785 
 786     XDrawLine(dpy, win, dimgc, 2, 2, 2, height-3);
 787     XDrawLine(dpy, win, dimgc, 2, height-3, width-bwidth-1, height-3);
 788     XDrawLine(dpy, win, dimgc, 2, 2, width-bwidth-2, 2);
 789     XDrawLine(dpy, win, dimgc, width-bwidth, 2, width-bwidth, height-3);
 790     if (statusWindow->fontset){
 791         XmbDrawString(dpy, win, statusWindow->fontset, fggc,
 792                       bwidth + 2, height - bwidth - 4,
 793                       statusWindow->status,
 794                       strlen(statusWindow->status));
 795     }
 796     else{
 797         /*too bad we failed to create a fontset for this locale*/
 798         XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4,
 799                     "[InputMethod ON]", strlen("[InputMethod ON]"));
 800     }
 801 }
 802 
 803 void statusWindowEventHandler(XEvent event){
 804     JNIEnv *env = GetJNIEnv();
 805     X11InputMethodData *pX11IMData = NULL;
 806     StatusWindow *statusWindow;
 807 
 808     if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) {
 809         currentX11InputMethodInstance = NULL;
 810         return;
 811     }
 812 
 813     if (NULL == currentX11InputMethodInstance
 814         || NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance))
 815         || NULL == (statusWindow = pX11IMData->statusWindow)
 816         || statusWindow->w != event.xany.window){
 817         return;
 818     }
 819 
 820     switch (event.type){
 821     case Expose:
 822         paintStatusWindow(statusWindow);
 823         break;
 824     case MapNotify:
 825     case ConfigureNotify:
 826         {
 827           /*need to reset the stackMode...*/
 828             XWindowChanges xwc;
 829             int value_make = CWStackMode;
 830             xwc.stack_mode = TopIf;
 831             XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
 832         }
 833         break;
 834         /*
 835     case UnmapNotify:
 836     case VisibilityNotify:
 837         break;
 838         */
 839     default:
 840         break;
 841   }
 842 }
 843 
 844 static void adjustStatusWindow(Window shell){
 845     JNIEnv *env = GetJNIEnv();
 846     X11InputMethodData *pX11IMData = NULL;
 847     StatusWindow *statusWindow;
 848 
 849     if (NULL == currentX11InputMethodInstance
 850         || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
 851         || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
 852         || NULL == (statusWindow = pX11IMData->statusWindow)
 853         || !statusWindow->on) {
 854         return;
 855     }
 856     {
 857         XWindowAttributes xwa;
 858         int x, y;
 859         Window child;
 860         XGetWindowAttributes(dpy, shell, &xwa);
 861         XTranslateCoordinates(dpy,
 862                               shell, xwa.root,
 863                               xwa.x, xwa.y,
 864                               &x, &y,
 865                               &child);
 866         if (statusWindow->x != x
 867             || statusWindow->y != y
 868             || statusWindow->height != xwa.height){
 869           statusWindow->x = x;
 870           statusWindow->y = y;
 871           statusWindow->height = xwa.height;
 872 
 873           x = statusWindow->x - statusWindow->off_x;
 874           y = statusWindow->y + statusWindow->height - statusWindow->off_y;
 875           if (x < 0 ){
 876               x = 0;
 877           }
 878           if (x + statusWindow->statusW > statusWindow->rootW){
 879               x = statusWindow->rootW - statusWindow->statusW;
 880           }
 881           if (y + statusWindow->statusH > statusWindow->rootH){
 882               y = statusWindow->rootH - statusWindow->statusH;
 883           }
 884           XMoveWindow(dpy, statusWindow->w, x, y);
 885         }
 886     }
 887 }
 888 #endif  /* __linux__ || MACOSX */
 889 /*
 890  * Creates two XICs, one for active clients and the other for passive
 891  * clients. All information on those XICs are stored in the
 892  * X11InputMethodData given by the pX11IMData parameter.
 893  *
 894  * For active clients: Try to use preedit callback to support
 895  * on-the-spot. If tc is not null, the XIC to be created will
 896  * share the Status Area with Motif widgets (TextComponents). If the
 897  * preferable styles can't be used, fallback to root-window styles. If
 898  * root-window styles failed, fallback to None styles.
 899  *
 900  * For passive clients: Try to use root-window styles. If failed,
 901  * fallback to None styles.
 902  */
 903 static Bool
 904 createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w)
 905 {
 906     XIC active_ic, passive_ic;
 907     XVaNestedList preedit = NULL;
 908     XVaNestedList status = NULL;
 909     XIMStyle on_the_spot_styles = XIMPreeditCallbacks,
 910              active_styles = 0,
 911              passive_styles = 0,
 912              no_styles = 0;
 913     XIMCallback *callbacks;
 914     unsigned short i;
 915     XIMStyles *im_styles;
 916     char *ret = NULL;
 917 
 918     if (X11im == NULL) {
 919         return False;
 920     }
 921     if (!w) {
 922         return False;
 923     }
 924 
 925     ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL);
 926 
 927     if (ret != NULL) {
 928         jio_fprintf(stderr,"XGetIMValues: %s\n",ret);
 929         return FALSE ;
 930     }
 931 
 932 #if defined(__linux__) || defined(MACOSX)
 933     on_the_spot_styles |= XIMStatusNothing;
 934 
 935     /*kinput does not support XIMPreeditCallbacks and XIMStatusArea
 936       at the same time, so use StatusCallback to draw the status
 937       ourself
 938     */
 939     for (i = 0; i < im_styles->count_styles; i++) {
 940         if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) {
 941             on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks);
 942             break;
 943         }
 944     }
 945 #else /*! __linux__ && !MACOSX */
 946     on_the_spot_styles |= XIMStatusNothing;
 947 #endif /* __linux__ || MACOSX */
 948 
 949     for (i = 0; i < im_styles->count_styles; i++) {
 950         active_styles |= im_styles->supported_styles[i] & on_the_spot_styles;
 951         passive_styles |= im_styles->supported_styles[i] & ROOT_WINDOW_STYLES;
 952         no_styles |= im_styles->supported_styles[i] & NO_STYLES;
 953     }
 954 
 955     XFree(im_styles);
 956 
 957     if (active_styles != on_the_spot_styles) {
 958         if (passive_styles == ROOT_WINDOW_STYLES)
 959             active_styles = passive_styles;
 960         else {
 961             if (no_styles == NO_STYLES)
 962                 active_styles = passive_styles = NO_STYLES;
 963             else
 964                 active_styles = passive_styles = 0;
 965         }
 966     } else {
 967         if (passive_styles != ROOT_WINDOW_STYLES) {
 968             if (no_styles == NO_STYLES)
 969                 active_styles = passive_styles = NO_STYLES;
 970             else
 971                 active_styles = passive_styles = 0;
 972         }
 973     }
 974 
 975     if (active_styles == on_the_spot_styles) {
 976         callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS);
 977         if (callbacks == (XIMCallback *)NULL)
 978             return False;
 979         pX11IMData->callbacks = callbacks;
 980 
 981         for (i = 0; i < NCALLBACKS; i++, callbacks++) {
 982             callbacks->client_data = (XPointer) pX11IMData->x11inputmethod;
 983             callbacks->callback = callback_funcs[i];
 984         }
 985 
 986         callbacks = pX11IMData->callbacks;
 987         preedit = (XVaNestedList)XVaCreateNestedList(0,
 988                         XNPreeditStartCallback, &callbacks[PreeditStartIndex],
 989                         XNPreeditDoneCallback,  &callbacks[PreeditDoneIndex],
 990                         XNPreeditDrawCallback,  &callbacks[PreeditDrawIndex],
 991                         XNPreeditCaretCallback, &callbacks[PreeditCaretIndex],
 992                         NULL);
 993         if (preedit == (XVaNestedList)NULL)
 994             goto err;
 995 #if defined(__linux__) || defined(MACOSX)
 996         /*always try XIMStatusCallbacks for active client...*/
 997         {
 998             status = (XVaNestedList)XVaCreateNestedList(0,
 999                         XNStatusStartCallback, &callbacks[StatusStartIndex],
1000                         XNStatusDoneCallback,  &callbacks[StatusDoneIndex],
1001                         XNStatusDrawCallback, &callbacks[StatusDrawIndex],
1002                         NULL);
1003 
1004             if (status == NULL)
1005                 goto err;
1006             pX11IMData->statusWindow = createStatusWindow(w);
1007             pX11IMData->ic_active = XCreateIC(X11im,
1008                                               XNClientWindow, w,
1009                                               XNFocusWindow, w,
1010                                               XNInputStyle, active_styles,
1011                                               XNPreeditAttributes, preedit,
1012                                               XNStatusAttributes, status,
1013                                               NULL);
1014             XFree((void *)status);
1015             XFree((void *)preedit);
1016         }
1017 #else /* !__linux__ && !MACOSX */
1018             pX11IMData->ic_active = XCreateIC(X11im,
1019                                               XNClientWindow, w,
1020                                               XNFocusWindow, w,
1021                                               XNInputStyle, active_styles,
1022                                               XNPreeditAttributes, preedit,
1023                                               NULL);
1024         XFree((void *)preedit);
1025 #endif /* __linux__ || MACOSX */
1026         pX11IMData->ic_passive = XCreateIC(X11im,
1027                                            XNClientWindow, w,
1028                                            XNFocusWindow, w,
1029                                            XNInputStyle, passive_styles,
1030                                            NULL);
1031 
1032     } else {
1033         pX11IMData->ic_active = XCreateIC(X11im,
1034                                           XNClientWindow, w,
1035                                           XNFocusWindow, w,
1036                                           XNInputStyle, active_styles,
1037                                           NULL);
1038         pX11IMData->ic_passive = pX11IMData->ic_active;
1039     }
1040 
1041     if (pX11IMData->ic_active == (XIC)0
1042         || pX11IMData->ic_passive == (XIC)0) {
1043         return False;
1044     }
1045 
1046     /*
1047      * Use commit string call back if possible.
1048      * This will ensure the correct order of preedit text and commit text
1049      */
1050     {
1051         XIMCallback cb;
1052         cb.client_data = (XPointer) pX11IMData->x11inputmethod;
1053         cb.callback = (XIMProc) CommitStringCallback;
1054         XSetICValues (pX11IMData->ic_active, XNCommitStringCallback, &cb, NULL);
1055         if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1056             XSetICValues (pX11IMData->ic_passive, XNCommitStringCallback, &cb, NULL);
1057         }
1058     }
1059 
1060     /* Add the global reference object to X11InputMethod to the list. */
1061     addToX11InputMethodGRefList(pX11IMData->x11inputmethod);
1062 
1063     return True;
1064 
1065  err:
1066     if (preedit)
1067         XFree((void *)preedit);
1068     THROW_OUT_OF_MEMORY_ERROR();
1069     return False;
1070 }
1071 
1072 static void
1073 PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1074 {
1075     /*ARGSUSED*/
1076     /* printf("Native: PreeditCaretCallback\n"); */
1077 }
1078 
1079 static void
1080 PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1081 {
1082     /*ARGSUSED*/
1083     /* printf("Native: StatusStartCallback\n"); */
1084 }
1085 
1086 /*
1087  * Translate the preedit draw callback items to Java values and invoke
1088  * X11InputMethod.dispatchComposedText().
1089  *
1090  * client_data: X11InputMethod object
1091  */
1092 static void
1093 PreeditDrawCallback(XIC ic, XPointer client_data,
1094                     XIMPreeditDrawCallbackStruct *pre_draw)
1095 {
1096     JNIEnv *env = GetJNIEnv();
1097     X11InputMethodData *pX11IMData = NULL;
1098     jmethodID x11imMethodID;
1099 
1100     XIMText *text;
1101     jstring javastr = NULL;
1102     jintArray style = NULL;
1103 
1104     /* printf("Native: PreeditDrawCallback() \n"); */
1105     if (pre_draw == NULL) {
1106         return;
1107     }
1108     AWT_LOCK();
1109     if (!isX11InputMethodGRefInList((jobject)client_data)) {
1110         if ((jobject)client_data == currentX11InputMethodInstance) {
1111             currentX11InputMethodInstance = NULL;
1112         }
1113         goto finally;
1114     }
1115     if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {
1116         goto finally;
1117     }
1118 
1119     if ((text = pre_draw->text) != NULL) {
1120         if (text->string.multi_byte != NULL) {
1121             if (pre_draw->text->encoding_is_wchar == False) {
1122                 javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte);
1123             } else {
1124                 char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1125                 if (mbstr == NULL) {
1126                     goto finally;
1127                 }
1128                 javastr = JNU_NewStringPlatform(env, (const char *)mbstr);
1129                 free(mbstr);
1130             }
1131         }
1132         if (text->feedback != NULL) {
1133             int cnt;
1134             jint *tmpstyle;
1135 
1136             style = (*env)->NewIntArray(env, text->length);
1137             if (JNU_IsNull(env, style)) {
1138                 THROW_OUT_OF_MEMORY_ERROR();
1139                 goto finally;
1140             }
1141 
1142             if (sizeof(XIMFeedback) == sizeof(jint)) {
1143                 /*
1144                  * Optimization to avoid copying the array
1145                  */
1146                 (*env)->SetIntArrayRegion(env, style, 0,
1147                                           text->length, (jint *)text->feedback);
1148             } else {
1149                 tmpstyle  = (jint *)malloc(sizeof(jint)*(text->length));
1150                 if (tmpstyle == (jint *) NULL) {
1151                     THROW_OUT_OF_MEMORY_ERROR();
1152                     goto finally;
1153                 }
1154                 for (cnt = 0; cnt < (int)text->length; cnt++)
1155                         tmpstyle[cnt] = text->feedback[cnt];
1156                 (*env)->SetIntArrayRegion(env, style, 0,
1157                                           text->length, (jint *)tmpstyle);
1158             }
1159         }
1160     }
1161     JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
1162                          "dispatchComposedText",
1163                          "(Ljava/lang/String;[IIIIJ)V",
1164                          javastr,
1165                          style,
1166                          (jint)pre_draw->chg_first,
1167                          (jint)pre_draw->chg_length,
1168                          (jint)pre_draw->caret,
1169                          awt_util_nowMillisUTC());
1170 finally:
1171     AWT_UNLOCK();
1172     return;
1173 }
1174 
1175 static void
1176 PreeditCaretCallback(XIC ic, XPointer client_data,
1177                      XIMPreeditCaretCallbackStruct *pre_caret)
1178 {
1179     /*ARGSUSED*/
1180     /* printf("Native: PreeditCaretCallback\n"); */
1181 
1182 }
1183 
1184 #if defined(__linux__) || defined(MACOSX)
1185 static void
1186 StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1187 {
1188     /*ARGSUSED*/
1189     /*printf("StatusStartCallback:\n");  */
1190 
1191 }
1192 
1193 static void
1194 StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1195 {
1196     /*ARGSUSED*/
1197     /*printf("StatusDoneCallback:\n"); */
1198 
1199 }
1200 
1201 static void
1202 StatusDrawCallback(XIC ic, XPointer client_data,
1203                      XIMStatusDrawCallbackStruct *status_draw)
1204 {
1205     /*ARGSUSED*/
1206     /*printf("StatusDrawCallback:\n"); */
1207     JNIEnv *env = GetJNIEnv();
1208     X11InputMethodData *pX11IMData = NULL;
1209     StatusWindow *statusWindow;
1210 
1211     AWT_LOCK();
1212 
1213     if (!isX11InputMethodGRefInList((jobject)client_data)) {
1214         if ((jobject)client_data == currentX11InputMethodInstance) {
1215             currentX11InputMethodInstance = NULL;
1216         }
1217         goto finally;
1218     }
1219 
1220     if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data))
1221         || NULL == (statusWindow = pX11IMData->statusWindow)){
1222         goto finally;
1223     }
1224    currentX11InputMethodInstance = (jobject)client_data;
1225 
1226     if (status_draw->type == XIMTextType){
1227         XIMText *text = (status_draw->data).text;
1228         if (text != NULL){
1229           if (text->string.multi_byte != NULL){
1230               strcpy(statusWindow->status, text->string.multi_byte);
1231           }
1232           else{
1233               char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1234               strcpy(statusWindow->status, mbstr);
1235           }
1236           statusWindow->on = True;
1237           onoffStatusWindow(pX11IMData, statusWindow->parent, True);
1238           paintStatusWindow(statusWindow);
1239         }
1240         else {
1241             statusWindow->on = False;
1242             /*just turnoff the status window
1243             paintStatusWindow(statusWindow);
1244             */
1245             onoffStatusWindow(pX11IMData, 0, False);
1246         }
1247     }
1248 
1249  finally:
1250     AWT_UNLOCK();
1251 }
1252 #endif /* __linux__ || MACOSX */
1253 
1254 static void CommitStringCallback(XIC ic, XPointer client_data, XPointer call_data) {
1255     JNIEnv *env = GetJNIEnv();
1256     XIMText * text = (XIMText *)call_data;
1257     X11InputMethodData *pX11IMData = NULL;
1258     jstring javastr;
1259 
1260     AWT_LOCK();
1261 
1262     if (!isX11InputMethodGRefInList((jobject)client_data)) {
1263         if ((jobject)client_data == currentX11InputMethodInstance) {
1264             currentX11InputMethodInstance = NULL;
1265         }
1266         goto finally;
1267     }
1268 
1269     if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {
1270         goto finally;
1271     }
1272     currentX11InputMethodInstance = (jobject)client_data;
1273 
1274     if (text->encoding_is_wchar == False) {
1275         javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte);
1276     } else {
1277         char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1278         if (mbstr == NULL) {
1279             goto finally;
1280         }
1281         javastr = JNU_NewStringPlatform(env, (const char *)mbstr);
1282         free(mbstr);
1283     }
1284 
1285     if (javastr != NULL) {
1286         JNU_CallMethodByName(env, NULL,
1287                                  pX11IMData->x11inputmethod,
1288                                  "dispatchCommittedText",
1289                                  "(Ljava/lang/String;J)V",
1290                                  javastr,
1291                                  awt_util_nowMillisUTC());
1292     }
1293  finally:
1294     AWT_UNLOCK();
1295 }
1296 
1297 static void OpenXIMCallback(Display *display, XPointer client_data, XPointer call_data) {
1298     XIMCallback ximCallback;
1299 
1300     X11im = XOpenIM(display, NULL, NULL, NULL);
1301     if (X11im == NULL) {
1302         return;
1303     }
1304 
1305     ximCallback.callback = (XIMProc)DestroyXIMCallback;
1306     ximCallback.client_data = NULL;
1307     XSetIMValues(X11im, XNDestroyCallback, &ximCallback, NULL);
1308 }
1309 
1310 static void DestroyXIMCallback(XIM im, XPointer client_data, XPointer call_data) {
1311     /* mark that XIM server was destroyed */
1312     X11im = NULL;
1313     JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1314     /* free the old pX11IMData and set it to null. this also avoids crashing
1315      * the jvm if the XIM server reappears */
1316     X11InputMethodData *pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
1317 }
1318 
1319 /*
1320  * Class:     sun_awt_X11InputMethod
1321  * Method:    initIDs
1322  * Signature: ()V
1323  */
1324 
1325 /* This function gets called from the static initializer for
1326    X11InputMethod.java
1327    to initialize the fieldIDs for fields that may be accessed from C */
1328 JNIEXPORT void JNICALL
1329 Java_sun_awt_X11InputMethod_initIDs(JNIEnv *env, jclass cls)
1330 {
1331     x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J");
1332 }
1333 
1334 
1335 JNIEXPORT jboolean JNICALL
1336 Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env,
1337                                           jobject this,
1338                                           jlong display)
1339 {
1340     Bool registered;
1341 
1342     AWT_LOCK();
1343 
1344     dpy = (Display *)jlong_to_ptr(display);
1345 
1346 /* Use IMInstantiate call back only on Linux, as there is a bug in Solaris
1347    (4768335)
1348 */
1349 #if defined(__linux__) || defined(MACOSX)
1350     registered = XRegisterIMInstantiateCallback(dpy, NULL, NULL,
1351                      NULL, (XIDProc)OpenXIMCallback, NULL);
1352     if (!registered) {
1353         /* directly call openXIM callback */
1354 #endif
1355         OpenXIMCallback(dpy, NULL, NULL);
1356 #if defined(__linux__) || defined(MACOSX)
1357     }
1358 #endif
1359 
1360     AWT_UNLOCK();
1361 
1362     return JNI_TRUE;
1363 }
1364 
1365 JNIEXPORT jboolean JNICALL
1366 Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env,
1367                                                   jobject this,
1368                                                   jlong window)
1369 {
1370     X11InputMethodData *pX11IMData;
1371     jobject globalRef;
1372     XIC ic;
1373 
1374     AWT_LOCK();
1375 
1376     if (!window) {
1377         JNU_ThrowNullPointerException(env, "NullPointerException");
1378         AWT_UNLOCK();
1379         return JNI_FALSE;
1380     }
1381 
1382     pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData));
1383     if (pX11IMData == NULL) {
1384         THROW_OUT_OF_MEMORY_ERROR();
1385         AWT_UNLOCK();
1386         return JNI_FALSE;
1387     }
1388 
1389     globalRef = (*env)->NewGlobalRef(env, this);
1390     pX11IMData->x11inputmethod = globalRef;
1391 #if defined(__linux__) || defined(MACOSX)
1392     pX11IMData->statusWindow = NULL;
1393 #endif /* __linux__ || MACOSX */
1394 
1395     pX11IMData->lookup_buf = 0;
1396     pX11IMData->lookup_buf_len = 0;
1397 
1398     if (createXIC(env, pX11IMData, (Window)window)
1399         == False) {
1400         destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData);
1401         pX11IMData = (X11InputMethodData *) NULL;
1402     }
1403 
1404     setX11InputMethodData(env, this, pX11IMData);
1405 
1406     AWT_UNLOCK();
1407     return (pX11IMData != NULL);
1408 }
1409 
1410 JNIEXPORT void JNICALL
1411 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env,
1412                                               jobject this,
1413                                               jlong w,
1414                                               jboolean req,
1415                                               jboolean active)
1416 {
1417     X11InputMethodData *pX11IMData;
1418     AWT_LOCK();
1419     pX11IMData = getX11InputMethodData(env, this);
1420     if (pX11IMData == NULL) {
1421         AWT_UNLOCK();
1422         return;
1423     }
1424 
1425     if (req) {
1426         if (!w) {
1427             AWT_UNLOCK();
1428             return;
1429         }
1430         pX11IMData->current_ic = active ?
1431                         pX11IMData->ic_active : pX11IMData->ic_passive;
1432         /*
1433          * On Solaris2.6, setXICWindowFocus() has to be invoked
1434          * before setting focus.
1435          */
1436         setXICWindowFocus(pX11IMData->current_ic, w);
1437         setXICFocus(pX11IMData->current_ic, req);
1438         currentX11InputMethodInstance = pX11IMData->x11inputmethod;
1439         currentFocusWindow =  w;
1440 #if defined(__linux__) || defined(MACOSX)
1441         if (active && pX11IMData->statusWindow && pX11IMData->statusWindow->on)
1442             onoffStatusWindow(pX11IMData, w, True);
1443 #endif
1444     } else {
1445         currentX11InputMethodInstance = NULL;
1446         currentFocusWindow = 0;
1447 #if defined(__linux__) || defined(MACOSX)
1448         onoffStatusWindow(pX11IMData, 0, False);
1449         if (pX11IMData->current_ic != NULL)
1450 #endif
1451         setXICFocus(pX11IMData->current_ic, req);
1452 
1453         pX11IMData->current_ic = (XIC)0;
1454     }
1455 
1456     XFlush(dpy);
1457     AWT_UNLOCK();
1458 }
1459 
1460 JNIEXPORT void JNICALL
1461 Java_sun_awt_X11InputMethod_turnoffStatusWindow(JNIEnv *env,
1462                                                 jobject this)
1463 {
1464 #if defined(__linux__) || defined(MACOSX)
1465     X11InputMethodData *pX11IMData;
1466     StatusWindow *statusWindow;
1467 
1468     AWT_LOCK();
1469 
1470     if (NULL == currentX11InputMethodInstance
1471         || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
1472         || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
1473         || NULL == (statusWindow = pX11IMData->statusWindow)
1474         || !statusWindow->on ){
1475         AWT_UNLOCK();
1476         return;
1477     }
1478     onoffStatusWindow(pX11IMData, 0, False);
1479 
1480     AWT_UNLOCK();
1481 #endif
1482 }
1483 
1484 JNIEXPORT void JNICALL
1485 Java_sun_awt_X11InputMethod_disposeXIC(JNIEnv *env,
1486                                              jobject this)
1487 {
1488     X11InputMethodData *pX11IMData = NULL;
1489 
1490     AWT_LOCK();
1491     pX11IMData = getX11InputMethodData(env, this);
1492     if (pX11IMData == NULL) {
1493         AWT_UNLOCK();
1494         return;
1495     }
1496 
1497     setX11InputMethodData(env, this, NULL);
1498 
1499     if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) {
1500         currentX11InputMethodInstance = NULL;
1501         currentFocusWindow = 0;
1502     }
1503     destroyX11InputMethodData(env, pX11IMData);
1504     AWT_UNLOCK();
1505 }
1506 
1507 JNIEXPORT jstring JNICALL
1508 Java_sun_awt_X11InputMethod_resetXIC(JNIEnv *env,
1509                                            jobject this)
1510 {
1511     X11InputMethodData *pX11IMData;
1512     char *xText = NULL;
1513     jstring jText = (jstring)0;
1514 
1515     AWT_LOCK();
1516     pX11IMData = getX11InputMethodData(env, this);
1517     if (pX11IMData == NULL) {
1518         AWT_UNLOCK();
1519         return jText;
1520     }
1521 
1522     if (pX11IMData->current_ic)
1523         xText = XmbResetIC(pX11IMData->current_ic);
1524     else {
1525         /*
1526          * If there is no reference to the current XIC, try to reset both XICs.
1527          */
1528         xText = XmbResetIC(pX11IMData->ic_active);
1529         /*it may also means that the real client component does
1530           not have focus -- has been deactivated... its xic should
1531           not have the focus, bug#4284651 showes reset XIC for htt
1532           may bring the focus back, so de-focus it again.
1533         */
1534         setXICFocus(pX11IMData->ic_active, FALSE);
1535         if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1536             char *tmpText = XmbResetIC(pX11IMData->ic_passive);
1537             setXICFocus(pX11IMData->ic_passive, FALSE);
1538             if (xText == (char *)NULL && tmpText)
1539                 xText = tmpText;
1540         }
1541 
1542     }
1543     if (xText != NULL) {
1544         jText = JNU_NewStringPlatform(env, (const char *)xText);
1545         XFree((void *)xText);
1546     }
1547 
1548     AWT_UNLOCK();
1549     return jText;
1550 }
1551 
1552 /*
1553  * Class:     sun_awt_X11InputMethod
1554  * Method:    setCompositionEnabledNative
1555  * Signature: (ZJ)V
1556  *
1557  * This method tries to set the XNPreeditState attribute associated with the current
1558  * XIC to the passed in 'enable' state.
1559  *
1560  * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the
1561  * 'enable' state; Otherwise, if XSetICValues fails to set this attribute,
1562  * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this
1563  * method fails due to other reasons.
1564  *
1565  */
1566 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_setCompositionEnabledNative
1567   (JNIEnv *env, jobject this, jboolean enable)
1568 {
1569     X11InputMethodData *pX11IMData;
1570     char * ret = NULL;
1571 
1572     AWT_LOCK();
1573     pX11IMData = getX11InputMethodData(env, this);
1574 
1575     if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1576         AWT_UNLOCK();
1577         return JNI_FALSE;
1578     }
1579 
1580     ret = XSetICValues(pX11IMData->current_ic, XNPreeditState,
1581                        (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL);
1582     AWT_UNLOCK();
1583 
1584     if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1585         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1586     }
1587 
1588     return (jboolean)(ret == 0);
1589 }
1590 
1591 /*
1592  * Class:     sun_awt_X11InputMethod
1593  * Method:    isCompositionEnabledNative
1594  * Signature: (J)Z
1595  *
1596  * This method tries to get the XNPreeditState attribute associated with the current XIC.
1597  *
1598  * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if
1599  * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException
1600  * will be thrown. JNI_FALSE is returned if this method fails due to other reasons.
1601  *
1602  */
1603 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_isCompositionEnabledNative
1604   (JNIEnv *env, jobject this)
1605 {
1606     X11InputMethodData *pX11IMData = NULL;
1607     char * ret = NULL;
1608     XIMPreeditState state;
1609 
1610     AWT_LOCK();
1611     pX11IMData = getX11InputMethodData(env, this);
1612 
1613     if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1614         AWT_UNLOCK();
1615         return JNI_FALSE;
1616     }
1617 
1618     ret = XGetICValues(pX11IMData->current_ic, XNPreeditState, &state, NULL);
1619     AWT_UNLOCK();
1620 
1621     if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1622         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1623         return JNI_FALSE;
1624     }
1625 
1626     return (jboolean)(state == XIMPreeditEnable);
1627 }
1628 
1629 JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow
1630   (JNIEnv *env, jobject this, jlong window)
1631 {
1632 #if defined(__linux__) || defined(MACOSX)
1633     AWT_LOCK();
1634     adjustStatusWindow(window);
1635     AWT_UNLOCK();
1636 #endif
1637 }