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