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 }