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