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