1 /* 2 * Copyright (c) 1997, 2010, 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_XComponentPeer.h> 40 #include <sun_awt_X11_XInputMethod.h> 41 42 #define THROW_OUT_OF_MEMORY_ERROR() \ 43 JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL) 44 #define SETARG(name, value) XtSetArg(args[argc], name, value); argc++ 45 46 struct X11InputMethodIDs { 47 jfieldID pData; 48 } x11InputMethodIDs; 49 50 static void PreeditStartCallback(XIC, XPointer, XPointer); 51 static void PreeditDoneCallback(XIC, XPointer, XPointer); 52 static void PreeditDrawCallback(XIC, XPointer, 53 XIMPreeditDrawCallbackStruct *); 54 static void PreeditCaretCallback(XIC, XPointer, 55 XIMPreeditCaretCallbackStruct *); 56 #if defined(__linux__) || defined(MACOSX) 57 static void StatusStartCallback(XIC, XPointer, XPointer); 58 static void StatusDoneCallback(XIC, XPointer, XPointer); 59 static void StatusDrawCallback(XIC, XPointer, 60 XIMStatusDrawCallbackStruct *); 61 #endif 62 63 #define ROOT_WINDOW_STYLES (XIMPreeditNothing | XIMStatusNothing) 64 #define NO_STYLES (XIMPreeditNone | XIMStatusNone) 65 66 #define PreeditStartIndex 0 67 #define PreeditDoneIndex 1 68 #define PreeditDrawIndex 2 69 #define PreeditCaretIndex 3 70 #if defined(__linux__) || defined(MACOSX) 71 #define StatusStartIndex 4 72 #define StatusDoneIndex 5 73 #define StatusDrawIndex 6 74 #define NCALLBACKS 7 75 #else 76 #define NCALLBACKS 4 77 #endif 78 79 /* 80 * Callback function pointers: the order has to match the *Index 81 * values above. 82 */ 83 static XIMProc callback_funcs[NCALLBACKS] = { 84 (XIMProc)PreeditStartCallback, 85 (XIMProc)PreeditDoneCallback, 86 (XIMProc)PreeditDrawCallback, 87 (XIMProc)PreeditCaretCallback, 88 #if defined(__linux__) || defined(MACOSX) 89 (XIMProc)StatusStartCallback, 90 (XIMProc)StatusDoneCallback, 91 (XIMProc)StatusDrawCallback, 92 #endif 93 }; 94 95 #if defined(__linux__) || defined(MACOSX) 96 #define MAX_STATUS_LEN 100 97 typedef struct { 98 Window w; /*status window id */ 99 Window root; /*the root window id */ 100 Window parent; /*parent shell window */ 101 int x, y; /*parent's upperleft position */ 102 int width, height; /*parent's width, height */ 103 GC lightGC; /*gc for light border */ 104 GC dimGC; /*gc for dim border */ 105 GC bgGC; /*normal painting */ 106 GC fgGC; /*normal painting */ 107 int statusW, statusH; /*status window's w, h */ 108 int rootW, rootH; /*root window's w, h */ 109 int bWidth; /*border width */ 110 char status[MAX_STATUS_LEN]; /*status text */ 111 XFontSet fontset; /*fontset for drawing */ 112 int off_x, off_y; 113 Bool on; /*if the status window on*/ 114 } StatusWindow; 115 #endif 116 117 /* 118 * X11InputMethodData keeps per X11InputMethod instance information. A pointer 119 * to this data structure is kept in an X11InputMethod object (pData). 120 */ 121 typedef struct _X11InputMethodData { 122 XIC current_ic; /* current X Input Context */ 123 XIC ic_active; /* X Input Context for active clients */ 124 XIC ic_passive; /* X Input Context for passive clients */ 125 XIMCallback *callbacks; /* callback parameters */ 126 jobject x11inputmethod; /* global ref to X11InputMethod instance */ 127 /* associated with the XIC */ 128 #if defined(__linux__) || defined(MACOSX) 129 StatusWindow *statusWindow; /* our own status window */ 130 #endif 131 char *lookup_buf; /* buffer used for XmbLookupString */ 132 int lookup_buf_len; /* lookup buffer size in bytes */ 133 } X11InputMethodData; 134 135 /* 136 * When XIC is created, a global reference is created for 137 * sun.awt.X11InputMethod object so that it could be used by the XIM callback 138 * functions. This could be a dangerous thing to do when the original 139 * X11InputMethod object is garbage collected and as a result, 140 * destroyX11InputMethodData is called to delete the global reference. 141 * If any XIM callback function still holds and uses the "already deleted" 142 * global reference, disaster is going to happen. So we have to maintain 143 * a list for these global references which is consulted first when the 144 * callback functions or any function tries to use "currentX11InputMethodObject" 145 * which always refers to the global reference try to use it. 146 * 147 */ 148 typedef struct _X11InputMethodGRefNode { 149 jobject inputMethodGRef; 150 struct _X11InputMethodGRefNode* next; 151 } X11InputMethodGRefNode; 152 153 X11InputMethodGRefNode *x11InputMethodGRefListHead = NULL; 154 155 /* reference to the current X11InputMethod instance, it is always 156 point to the global reference to the X11InputMethodObject since 157 it could be referenced by different threads. */ 158 jobject currentX11InputMethodInstance = NULL; 159 160 Window currentFocusWindow = 0; /* current window that has focus for input 161 method. (the best place to put this 162 information should be 163 currentX11InputMethodInstance's pData) */ 164 static XIM X11im = NULL; 165 Display * dpy = NULL; 166 167 #define GetJNIEnv() (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2) 168 169 static void DestroyXIMCallback(XIM, XPointer, XPointer); 170 static void OpenXIMCallback(Display *, XPointer, XPointer); 171 /* Solaris XIM Extention */ 172 #define XNCommitStringCallback "commitStringCallback" 173 static void CommitStringCallback(XIC, XPointer, XPointer); 174 175 static X11InputMethodData * getX11InputMethodData(JNIEnv *, jobject); 176 static void setX11InputMethodData(JNIEnv *, jobject, X11InputMethodData *); 177 static void destroyX11InputMethodData(JNIEnv *, X11InputMethodData *); 178 static void freeX11InputMethodData(JNIEnv *, X11InputMethodData *); 179 180 #ifdef __solaris__ 181 /* Prototype for this function is missing in Solaris X11R6 Xlib.h */ 182 extern char *XSetIMValues( 183 #if NeedVarargsPrototypes 184 XIM /* im */, ... 185 #endif 186 ); 187 #endif 188 189 #ifdef XAWT_HACK 190 /* 191 * This function is stolen from /src/solaris/hpi/src/system_md.c 192 * It is used in setting the time in Java-level InputEvents 193 */ 194 jlong 195 awt_util_nowMillisUTC() 196 { 197 struct timeval t; 198 gettimeofday(&t, NULL); 199 return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000); 200 } 201 #endif /* XAWT_HACK */ 202 203 /* 204 * Converts the wchar_t string to a multi-byte string calling wcstombs(). A 205 * buffer is allocated by malloc() to store the multi-byte string. NULL is 206 * returned if the given wchar_t string pointer is NULL or buffer allocation is 207 * failed. 208 */ 209 static char * 210 wcstombsdmp(wchar_t *wcs, int len) 211 { 212 size_t n; 213 char *mbs; 214 215 if (wcs == NULL) 216 return NULL; 217 218 n = len*MB_CUR_MAX + 1; 219 220 mbs = (char *) malloc(n * sizeof(char)); 221 if (mbs == NULL) { 222 THROW_OUT_OF_MEMORY_ERROR(); 223 return NULL; 224 } 225 226 /* TODO: check return values... Handle invalid characters properly... */ 227 if (wcstombs(mbs, wcs, n) == (size_t)-1) 228 return NULL; 229 230 return mbs; 231 } 232 233 /* 234 * Returns True if the global reference is still in the list, 235 * otherwise False. 236 */ 237 static Bool isX11InputMethodGRefInList(jobject imGRef) { 238 X11InputMethodGRefNode *pX11InputMethodGRef = x11InputMethodGRefListHead; 239 240 if (imGRef == NULL) { 241 return False; 242 } 243 244 while (pX11InputMethodGRef != NULL) { 245 if (pX11InputMethodGRef->inputMethodGRef == imGRef) { 246 return True; 247 } 248 pX11InputMethodGRef = pX11InputMethodGRef->next; 249 } 250 251 return False; 252 } 253 254 /* 255 * Add the new created global reference to the list. 256 */ 257 static void addToX11InputMethodGRefList(jobject newX11InputMethodGRef) { 258 X11InputMethodGRefNode *newNode = NULL; 259 260 if (newX11InputMethodGRef == NULL || 261 isX11InputMethodGRefInList(newX11InputMethodGRef)) { 262 return; 263 } 264 265 newNode = (X11InputMethodGRefNode *)malloc(sizeof(X11InputMethodGRefNode)); 266 267 if (newNode == NULL) { 268 return; 269 } else { 270 newNode->inputMethodGRef = newX11InputMethodGRef; 271 newNode->next = x11InputMethodGRefListHead; 272 x11InputMethodGRefListHead = newNode; 273 } 274 } 275 276 /* 277 * Remove the global reference from the list. 278 */ 279 static void removeX11InputMethodGRefFromList(jobject x11InputMethodGRef) { 280 X11InputMethodGRefNode *pX11InputMethodGRef = NULL; 281 X11InputMethodGRefNode *cX11InputMethodGRef = x11InputMethodGRefListHead; 282 283 if (x11InputMethodGRefListHead == NULL || 284 x11InputMethodGRef == NULL) { 285 return; 286 } 287 288 /* cX11InputMethodGRef always refers to the current node while 289 pX11InputMethodGRef refers to the previous node. 290 */ 291 while (cX11InputMethodGRef != NULL) { 292 if (cX11InputMethodGRef->inputMethodGRef == x11InputMethodGRef) { 293 break; 294 } 295 pX11InputMethodGRef = cX11InputMethodGRef; 296 cX11InputMethodGRef = cX11InputMethodGRef->next; 297 } 298 299 if (cX11InputMethodGRef == NULL) { 300 return; /* Not found. */ 301 } 302 303 if (cX11InputMethodGRef == x11InputMethodGRefListHead) { 304 x11InputMethodGRefListHead = x11InputMethodGRefListHead->next; 305 } else { 306 pX11InputMethodGRef->next = cX11InputMethodGRef->next; 307 } 308 free(cX11InputMethodGRef); 309 310 return; 311 } 312 313 314 static X11InputMethodData * getX11InputMethodData(JNIEnv * env, jobject imInstance) { 315 X11InputMethodData *pX11IMData = 316 (X11InputMethodData *)JNU_GetLongFieldAsPtr(env, imInstance, x11InputMethodIDs.pData); 317 318 /* 319 * In case the XIM server was killed somehow, reset X11InputMethodData. 320 */ 321 if (X11im == NULL && pX11IMData != NULL) { 322 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, 323 "flushText", 324 "()V"); 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 Bool 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 Bool result = True; 464 static Bool 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 #ifndef XAWT_HACK 551 awt_util_nowMillisUTC_offset(event->time)); 552 #else 553 event->time); 554 #endif 555 } 556 break; 557 558 case XLookupKeySym: 559 /* 560 printf("lookupString: status=XLookupKeySym, type=%d, state=%x, keycode=%x, keysym=%x\n", 561 event->type, event->state, event->keycode, keysym); 562 */ 563 if (keysym == XK_Multi_key) 564 composing = True; 565 if (! composing) { 566 *keysymp = keysym; 567 result = False; 568 } 569 break; 570 571 case XLookupNone: 572 /* 573 printf("lookupString: status=XLookupNone, type=%d, state=%x, keycode=%x, keysym=%x\n", 574 event->type, event->state, event->keycode, keysym); 575 */ 576 break; 577 } 578 579 return result; 580 } 581 582 #if defined(__linux__) || defined(MACOSX) 583 static StatusWindow *createStatusWindow( 584 Window parent) { 585 StatusWindow *statusWindow; 586 XSetWindowAttributes attrib; 587 unsigned long attribmask; 588 Window containerWindow; 589 Window status; 590 Window child; 591 XWindowAttributes xwa; 592 XWindowAttributes xxwa; 593 /* Variable for XCreateFontSet()*/ 594 char **mclr; 595 int mccr = 0; 596 char *dsr; 597 Pixel bg, fg, light, dim; 598 int x, y, off_x, off_y, xx, yy; 599 unsigned int w, h, bw, depth; 600 XGCValues values; 601 unsigned long valuemask = 0; /*ignore XGCvalue and use defaults*/ 602 int screen = 0; 603 int i; 604 AwtGraphicsConfigDataPtr adata; 605 extern int awt_numScreens; 606 /*hardcode the size right now, should get the size base on font*/ 607 int width=80, height=22; 608 Window rootWindow; 609 Window *ignoreWindowPtr; 610 unsigned int ignoreUnit; 611 612 XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth); 613 614 attrib.override_redirect = True; 615 attribmask = CWOverrideRedirect; 616 for (i = 0; i < awt_numScreens; i++) { 617 if (RootWindow(dpy, i) == rootWindow) { 618 screen = i; 619 break; 620 } 621 } 622 adata = getDefaultConfig(screen); 623 bg = adata->AwtColorMatch(255, 255, 255, adata); 624 fg = adata->AwtColorMatch(0, 0, 0, adata); 625 light = adata->AwtColorMatch(195, 195, 195, adata); 626 dim = adata->AwtColorMatch(128, 128, 128, adata); 627 628 XGetWindowAttributes(dpy, parent, &xwa); 629 bw = 2; /*xwa.border_width does not have the correct value*/ 630 631 /*compare the size difference between parent container 632 and shell widget, the diff should be the border frame 633 and title bar height (?)*/ 634 635 XQueryTree( dpy, 636 parent, 637 &rootWindow, 638 &containerWindow, 639 &ignoreWindowPtr, 640 &ignoreUnit); 641 XGetWindowAttributes(dpy, containerWindow, &xxwa); 642 643 off_x = (xxwa.width - xwa.width) / 2; 644 off_y = xxwa.height - xwa.height - off_x; /*it's magic:-) */ 645 646 /*get the size of root window*/ 647 XGetWindowAttributes(dpy, rootWindow, &xxwa); 648 649 XTranslateCoordinates(dpy, 650 parent, xwa.root, 651 xwa.x, xwa.y, 652 &x, &y, 653 &child); 654 xx = x - off_x; 655 yy = y + xwa.height - off_y; 656 if (xx < 0 ){ 657 xx = 0; 658 } 659 if (xx + width > xxwa.width){ 660 xx = xxwa.width - width; 661 } 662 if (yy + height > xxwa.height){ 663 yy = xxwa.height - height; 664 } 665 666 status = XCreateWindow(dpy, 667 xwa.root, 668 xx, yy, 669 width, height, 670 0, 671 xwa.depth, 672 InputOutput, 673 adata->awt_visInfo.visual, 674 attribmask, &attrib); 675 XSelectInput(dpy, status, 676 ExposureMask | StructureNotifyMask | EnterWindowMask | 677 LeaveWindowMask | VisibilityChangeMask); 678 statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow)); 679 if (statusWindow == NULL){ 680 THROW_OUT_OF_MEMORY_ERROR(); 681 return NULL; 682 } 683 statusWindow->w = status; 684 //12-point font 685 statusWindow->fontset = XCreateFontSet(dpy, 686 "-*-*-medium-r-normal-*-*-120-*-*-*-*", 687 &mclr, &mccr, &dsr); 688 /* In case we didn't find the font set, release the list of missing characters */ 689 if (mccr > 0) { 690 XFreeStringList(mclr); 691 } 692 statusWindow->parent = parent; 693 statusWindow->on = False; 694 statusWindow->x = x; 695 statusWindow->y = y; 696 statusWindow->width = xwa.width; 697 statusWindow->height = xwa.height; 698 statusWindow->off_x = off_x; 699 statusWindow->off_y = off_y; 700 statusWindow->bWidth = bw; 701 statusWindow->statusH = height; 702 statusWindow->statusW = width; 703 statusWindow->rootH = xxwa.height; 704 statusWindow->rootW = xxwa.width; 705 statusWindow->lightGC = XCreateGC(dpy, status, valuemask, &values); 706 XSetForeground(dpy, statusWindow->lightGC, light); 707 statusWindow->dimGC = XCreateGC(dpy, status, valuemask, &values); 708 XSetForeground(dpy, statusWindow->dimGC, dim); 709 statusWindow->fgGC = XCreateGC(dpy, status, valuemask, &values); 710 XSetForeground(dpy, statusWindow->fgGC, fg); 711 statusWindow->bgGC = XCreateGC(dpy, status, valuemask, &values); 712 XSetForeground(dpy, statusWindow->bgGC, bg); 713 return statusWindow; 714 } 715 716 /* This method is to turn off or turn on the status window. */ 717 static void onoffStatusWindow(X11InputMethodData* pX11IMData, 718 Window parent, 719 Bool ON){ 720 XWindowAttributes xwa; 721 Window child; 722 int x, y; 723 StatusWindow *statusWindow = NULL; 724 725 if (NULL == currentX11InputMethodInstance || 726 NULL == pX11IMData || 727 NULL == (statusWindow = pX11IMData->statusWindow)){ 728 return; 729 } 730 731 if (ON == False){ 732 XUnmapWindow(dpy, statusWindow->w); 733 statusWindow->on = False; 734 return; 735 } 736 parent = JNU_CallMethodByName(GetJNIEnv(), NULL, pX11IMData->x11inputmethod, 737 "getCurrentParentWindow", 738 "()J").j; 739 if (statusWindow->parent != parent){ 740 statusWindow->parent = parent; 741 } 742 XGetWindowAttributes(dpy, parent, &xwa); 743 XTranslateCoordinates(dpy, 744 parent, xwa.root, 745 xwa.x, xwa.y, 746 &x, &y, 747 &child); 748 if (statusWindow->x != x 749 || statusWindow->y != y 750 || statusWindow->height != xwa.height){ 751 statusWindow->x = x; 752 statusWindow->y = y; 753 statusWindow->height = xwa.height; 754 x = statusWindow->x - statusWindow->off_x; 755 y = statusWindow->y + statusWindow->height - statusWindow->off_y; 756 if (x < 0 ){ 757 x = 0; 758 } 759 if (x + statusWindow->statusW > statusWindow->rootW){ 760 x = statusWindow->rootW - statusWindow->statusW; 761 } 762 if (y + statusWindow->statusH > statusWindow->rootH){ 763 y = statusWindow->rootH - statusWindow->statusH; 764 } 765 XMoveWindow(dpy, statusWindow->w, x, y); 766 } 767 statusWindow->on = True; 768 XMapWindow(dpy, statusWindow->w); 769 } 770 771 void paintStatusWindow(StatusWindow *statusWindow){ 772 Window win = statusWindow->w; 773 GC lightgc = statusWindow->lightGC; 774 GC dimgc = statusWindow->dimGC; 775 GC bggc = statusWindow->bgGC; 776 GC fggc = statusWindow->fgGC; 777 778 int width = statusWindow->statusW; 779 int height = statusWindow->statusH; 780 int bwidth = statusWindow->bWidth; 781 XFillRectangle(dpy, win, bggc, 0, 0, width, height); 782 /* draw border */ 783 XDrawLine(dpy, win, fggc, 0, 0, width, 0); 784 XDrawLine(dpy, win, fggc, 0, height-1, width-1, height-1); 785 XDrawLine(dpy, win, fggc, 0, 0, 0, height-1); 786 XDrawLine(dpy, win, fggc, width-1, 0, width-1, height-1); 787 788 XDrawLine(dpy, win, lightgc, 1, 1, width-bwidth, 1); 789 XDrawLine(dpy, win, lightgc, 1, 1, 1, height-2); 790 XDrawLine(dpy, win, lightgc, 1, height-2, width-bwidth, height-2); 791 XDrawLine(dpy, win, lightgc, width-bwidth-1, 1, width-bwidth-1, height-2); 792 793 XDrawLine(dpy, win, dimgc, 2, 2, 2, height-3); 794 XDrawLine(dpy, win, dimgc, 2, height-3, width-bwidth-1, height-3); 795 XDrawLine(dpy, win, dimgc, 2, 2, width-bwidth-2, 2); 796 XDrawLine(dpy, win, dimgc, width-bwidth, 2, width-bwidth, height-3); 797 if (statusWindow->fontset){ 798 XmbDrawString(dpy, win, statusWindow->fontset, fggc, 799 bwidth + 2, height - bwidth - 4, 800 statusWindow->status, 801 strlen(statusWindow->status)); 802 } 803 else{ 804 /*too bad we failed to create a fontset for this locale*/ 805 XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4, 806 "[InputMethod ON]", strlen("[InputMethod ON]")); 807 } 808 } 809 810 void statusWindowEventHandler(XEvent event){ 811 JNIEnv *env = GetJNIEnv(); 812 X11InputMethodData *pX11IMData = NULL; 813 StatusWindow *statusWindow; 814 815 if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) { 816 currentX11InputMethodInstance = NULL; 817 return; 818 } 819 820 if (NULL == currentX11InputMethodInstance 821 || NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance)) 822 || NULL == (statusWindow = pX11IMData->statusWindow) 823 || statusWindow->w != event.xany.window){ 824 return; 825 } 826 827 switch (event.type){ 828 case Expose: 829 paintStatusWindow(statusWindow); 830 break; 831 case MapNotify: 832 case ConfigureNotify: 833 { 834 /*need to reset the stackMode...*/ 835 XWindowChanges xwc; 836 int value_make = CWStackMode; 837 xwc.stack_mode = TopIf; 838 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); 839 } 840 break; 841 /* 842 case UnmapNotify: 843 case VisibilityNotify: 844 break; 845 */ 846 default: 847 break; 848 } 849 } 850 851 static void adjustStatusWindow(Window shell){ 852 JNIEnv *env = GetJNIEnv(); 853 X11InputMethodData *pX11IMData = NULL; 854 StatusWindow *statusWindow; 855 856 if (NULL == currentX11InputMethodInstance 857 || !isX11InputMethodGRefInList(currentX11InputMethodInstance) 858 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance)) 859 || NULL == (statusWindow = pX11IMData->statusWindow) 860 || !statusWindow->on) { 861 return; 862 } 863 { 864 XWindowAttributes xwa; 865 int x, y; 866 Window child; 867 XGetWindowAttributes(dpy, shell, &xwa); 868 XTranslateCoordinates(dpy, 869 shell, xwa.root, 870 xwa.x, xwa.y, 871 &x, &y, 872 &child); 873 if (statusWindow->x != x 874 || statusWindow->y != y 875 || statusWindow->height != xwa.height){ 876 statusWindow->x = x; 877 statusWindow->y = y; 878 statusWindow->height = xwa.height; 879 880 x = statusWindow->x - statusWindow->off_x; 881 y = statusWindow->y + statusWindow->height - statusWindow->off_y; 882 if (x < 0 ){ 883 x = 0; 884 } 885 if (x + statusWindow->statusW > statusWindow->rootW){ 886 x = statusWindow->rootW - statusWindow->statusW; 887 } 888 if (y + statusWindow->statusH > statusWindow->rootH){ 889 y = statusWindow->rootH - statusWindow->statusH; 890 } 891 XMoveWindow(dpy, statusWindow->w, x, y); 892 } 893 } 894 } 895 #endif /* __linux__ || MACOSX */ 896 /* 897 * Creates two XICs, one for active clients and the other for passive 898 * clients. All information on those XICs are stored in the 899 * X11InputMethodData given by the pX11IMData parameter. 900 * 901 * For active clients: Try to use preedit callback to support 902 * on-the-spot. If tc is not null, the XIC to be created will 903 * share the Status Area with Motif widgets (TextComponents). If the 904 * preferable styles can't be used, fallback to root-window styles. If 905 * root-window styles failed, fallback to None styles. 906 * 907 * For passive clients: Try to use root-window styles. If failed, 908 * fallback to None styles. 909 */ 910 static Bool 911 createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w) 912 { 913 XIC active_ic, passive_ic; 914 XVaNestedList preedit = NULL; 915 XVaNestedList status = NULL; 916 XIMStyle on_the_spot_styles = XIMPreeditCallbacks, 917 active_styles = 0, 918 passive_styles = 0, 919 no_styles = 0; 920 XIMCallback *callbacks; 921 unsigned short i; 922 XIMStyles *im_styles; 923 char *ret = NULL; 924 925 if (X11im == NULL) { 926 return False; 927 } 928 if (!w) { 929 return False; 930 } 931 932 ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL); 933 934 if (ret != NULL) { 935 jio_fprintf(stderr,"XGetIMValues: %s\n",ret); 936 return FALSE ; 937 } 938 939 #if defined(__linux__) || defined(MACOSX) 940 on_the_spot_styles |= XIMStatusNothing; 941 942 /*kinput does not support XIMPreeditCallbacks and XIMStatusArea 943 at the same time, so use StatusCallback to draw the status 944 ourself 945 */ 946 for (i = 0; i < im_styles->count_styles; i++) { 947 if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) { 948 on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks); 949 break; 950 } 951 } 952 #else /*! __linux__ && !MACOSX */ 953 on_the_spot_styles |= XIMStatusNothing; 954 #endif /* __linux__ || MACOSX */ 955 956 for (i = 0; i < im_styles->count_styles; i++) { 957 active_styles |= im_styles->supported_styles[i] & on_the_spot_styles; 958 passive_styles |= im_styles->supported_styles[i] & ROOT_WINDOW_STYLES; 959 no_styles |= im_styles->supported_styles[i] & NO_STYLES; 960 } 961 962 XFree(im_styles); 963 964 if (active_styles != on_the_spot_styles) { 965 if (passive_styles == ROOT_WINDOW_STYLES) 966 active_styles = passive_styles; 967 else { 968 if (no_styles == NO_STYLES) 969 active_styles = passive_styles = NO_STYLES; 970 else 971 active_styles = passive_styles = 0; 972 } 973 } else { 974 if (passive_styles != ROOT_WINDOW_STYLES) { 975 if (no_styles == NO_STYLES) 976 active_styles = passive_styles = NO_STYLES; 977 else 978 active_styles = passive_styles = 0; 979 } 980 } 981 982 if (active_styles == on_the_spot_styles) { 983 callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS); 984 if (callbacks == (XIMCallback *)NULL) 985 return False; 986 pX11IMData->callbacks = callbacks; 987 988 for (i = 0; i < NCALLBACKS; i++, callbacks++) { 989 callbacks->client_data = (XPointer) pX11IMData->x11inputmethod; 990 callbacks->callback = callback_funcs[i]; 991 } 992 993 callbacks = pX11IMData->callbacks; 994 preedit = (XVaNestedList)XVaCreateNestedList(0, 995 XNPreeditStartCallback, &callbacks[PreeditStartIndex], 996 XNPreeditDoneCallback, &callbacks[PreeditDoneIndex], 997 XNPreeditDrawCallback, &callbacks[PreeditDrawIndex], 998 XNPreeditCaretCallback, &callbacks[PreeditCaretIndex], 999 NULL); 1000 if (preedit == (XVaNestedList)NULL) 1001 goto err; 1002 #if defined(__linux__) || defined(MACOSX) 1003 /*always try XIMStatusCallbacks for active client...*/ 1004 { 1005 status = (XVaNestedList)XVaCreateNestedList(0, 1006 XNStatusStartCallback, &callbacks[StatusStartIndex], 1007 XNStatusDoneCallback, &callbacks[StatusDoneIndex], 1008 XNStatusDrawCallback, &callbacks[StatusDrawIndex], 1009 NULL); 1010 1011 if (status == NULL) 1012 goto err; 1013 pX11IMData->statusWindow = createStatusWindow(w); 1014 pX11IMData->ic_active = XCreateIC(X11im, 1015 XNClientWindow, w, 1016 XNFocusWindow, w, 1017 XNInputStyle, active_styles, 1018 XNPreeditAttributes, preedit, 1019 XNStatusAttributes, status, 1020 NULL); 1021 XFree((void *)status); 1022 XFree((void *)preedit); 1023 } 1024 #else /* !__linux__ && !MACOSX */ 1025 pX11IMData->ic_active = XCreateIC(X11im, 1026 XNClientWindow, w, 1027 XNFocusWindow, w, 1028 XNInputStyle, active_styles, 1029 XNPreeditAttributes, preedit, 1030 NULL); 1031 XFree((void *)preedit); 1032 #endif /* __linux__ || MACOSX */ 1033 pX11IMData->ic_passive = XCreateIC(X11im, 1034 XNClientWindow, w, 1035 XNFocusWindow, w, 1036 XNInputStyle, passive_styles, 1037 NULL); 1038 1039 } else { 1040 pX11IMData->ic_active = XCreateIC(X11im, 1041 XNClientWindow, w, 1042 XNFocusWindow, w, 1043 XNInputStyle, active_styles, 1044 NULL); 1045 pX11IMData->ic_passive = pX11IMData->ic_active; 1046 } 1047 1048 if (pX11IMData->ic_active == (XIC)0 1049 || pX11IMData->ic_passive == (XIC)0) { 1050 return False; 1051 } 1052 1053 /* 1054 * Use commit string call back if possible. 1055 * This will ensure the correct order of preedit text and commit text 1056 */ 1057 { 1058 XIMCallback cb; 1059 cb.client_data = (XPointer) pX11IMData->x11inputmethod; 1060 cb.callback = (XIMProc) CommitStringCallback; 1061 XSetICValues (pX11IMData->ic_active, XNCommitStringCallback, &cb, NULL); 1062 if (pX11IMData->ic_active != pX11IMData->ic_passive) { 1063 XSetICValues (pX11IMData->ic_passive, XNCommitStringCallback, &cb, NULL); 1064 } 1065 } 1066 1067 /* Add the global reference object to X11InputMethod to the list. */ 1068 addToX11InputMethodGRefList(pX11IMData->x11inputmethod); 1069 1070 return True; 1071 1072 err: 1073 if (preedit) 1074 XFree((void *)preedit); 1075 THROW_OUT_OF_MEMORY_ERROR(); 1076 return False; 1077 } 1078 1079 static void 1080 PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data) 1081 { 1082 /*ARGSUSED*/ 1083 /* printf("Native: PreeditCaretCallback\n"); */ 1084 } 1085 1086 static void 1087 PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data) 1088 { 1089 /*ARGSUSED*/ 1090 /* printf("Native: StatusStartCallback\n"); */ 1091 } 1092 1093 /* 1094 * Translate the preedit draw callback items to Java values and invoke 1095 * X11InputMethod.dispatchComposedText(). 1096 * 1097 * client_data: X11InputMethod object 1098 */ 1099 static void 1100 PreeditDrawCallback(XIC ic, XPointer client_data, 1101 XIMPreeditDrawCallbackStruct *pre_draw) 1102 { 1103 JNIEnv *env = GetJNIEnv(); 1104 X11InputMethodData *pX11IMData = NULL; 1105 jmethodID x11imMethodID; 1106 1107 XIMText *text; 1108 jstring javastr = NULL; 1109 jintArray style = NULL; 1110 1111 /* printf("Native: PreeditDrawCallback() \n"); */ 1112 if (pre_draw == NULL) { 1113 return; 1114 } 1115 AWT_LOCK(); 1116 if (!isX11InputMethodGRefInList((jobject)client_data)) { 1117 if ((jobject)client_data == currentX11InputMethodInstance) { 1118 currentX11InputMethodInstance = NULL; 1119 } 1120 goto finally; 1121 } 1122 if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) { 1123 goto finally; 1124 } 1125 1126 if ((text = pre_draw->text) != NULL) { 1127 if (text->string.multi_byte != NULL) { 1128 if (pre_draw->text->encoding_is_wchar == False) { 1129 javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte); 1130 } else { 1131 char *mbstr = wcstombsdmp(text->string.wide_char, text->length); 1132 if (mbstr == NULL) { 1133 goto finally; 1134 } 1135 javastr = JNU_NewStringPlatform(env, (const char *)mbstr); 1136 free(mbstr); 1137 } 1138 } 1139 if (text->feedback != NULL) { 1140 int cnt; 1141 jint *tmpstyle; 1142 1143 style = (*env)->NewIntArray(env, text->length); 1144 if (JNU_IsNull(env, style)) { 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) 1406 == False) { 1407 destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData); 1408 pX11IMData = (X11InputMethodData *) NULL; 1409 } 1410 1411 setX11InputMethodData(env, this, pX11IMData); 1412 1413 AWT_UNLOCK(); 1414 return (pX11IMData != NULL); 1415 } 1416 1417 JNIEXPORT void JNICALL 1418 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env, 1419 jobject this, 1420 jlong w, 1421 jboolean req, 1422 jboolean active) 1423 { 1424 X11InputMethodData *pX11IMData; 1425 AWT_LOCK(); 1426 pX11IMData = getX11InputMethodData(env, this); 1427 if (pX11IMData == NULL) { 1428 AWT_UNLOCK(); 1429 return; 1430 } 1431 1432 if (req) { 1433 if (!w) { 1434 AWT_UNLOCK(); 1435 return; 1436 } 1437 pX11IMData->current_ic = active ? 1438 pX11IMData->ic_active : pX11IMData->ic_passive; 1439 /* 1440 * On Solaris2.6, setXICWindowFocus() has to be invoked 1441 * before setting focus. 1442 */ 1443 setXICWindowFocus(pX11IMData->current_ic, w); 1444 setXICFocus(pX11IMData->current_ic, req); 1445 currentX11InputMethodInstance = pX11IMData->x11inputmethod; 1446 currentFocusWindow = w; 1447 #if defined(__linux__) || defined(MACOSX) 1448 if (active && pX11IMData->statusWindow && pX11IMData->statusWindow->on) 1449 onoffStatusWindow(pX11IMData, w, True); 1450 #endif 1451 } else { 1452 currentX11InputMethodInstance = NULL; 1453 currentFocusWindow = 0; 1454 #if defined(__linux__) || defined(MACOSX) 1455 onoffStatusWindow(pX11IMData, 0, False); 1456 if (pX11IMData->current_ic != NULL) 1457 #endif 1458 setXICFocus(pX11IMData->current_ic, req); 1459 1460 pX11IMData->current_ic = (XIC)0; 1461 } 1462 1463 XFlush(dpy); 1464 AWT_UNLOCK(); 1465 } 1466 1467 JNIEXPORT void JNICALL 1468 Java_sun_awt_X11InputMethod_turnoffStatusWindow(JNIEnv *env, 1469 jobject this) 1470 { 1471 #if defined(__linux__) || defined(MACOSX) 1472 X11InputMethodData *pX11IMData; 1473 StatusWindow *statusWindow; 1474 1475 AWT_LOCK(); 1476 1477 if (NULL == currentX11InputMethodInstance 1478 || !isX11InputMethodGRefInList(currentX11InputMethodInstance) 1479 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance)) 1480 || NULL == (statusWindow = pX11IMData->statusWindow) 1481 || !statusWindow->on ){ 1482 AWT_UNLOCK(); 1483 return; 1484 } 1485 onoffStatusWindow(pX11IMData, 0, False); 1486 1487 AWT_UNLOCK(); 1488 #endif 1489 } 1490 1491 JNIEXPORT void JNICALL 1492 Java_sun_awt_X11InputMethod_disposeXIC(JNIEnv *env, 1493 jobject this) 1494 { 1495 X11InputMethodData *pX11IMData = NULL; 1496 1497 AWT_LOCK(); 1498 pX11IMData = getX11InputMethodData(env, this); 1499 if (pX11IMData == NULL) { 1500 AWT_UNLOCK(); 1501 return; 1502 } 1503 1504 setX11InputMethodData(env, this, NULL); 1505 1506 if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) { 1507 currentX11InputMethodInstance = NULL; 1508 currentFocusWindow = 0; 1509 } 1510 destroyX11InputMethodData(env, pX11IMData); 1511 AWT_UNLOCK(); 1512 } 1513 1514 JNIEXPORT jstring JNICALL 1515 Java_sun_awt_X11InputMethod_resetXIC(JNIEnv *env, 1516 jobject this) 1517 { 1518 X11InputMethodData *pX11IMData; 1519 char *xText = NULL; 1520 jstring jText = (jstring)0; 1521 1522 AWT_LOCK(); 1523 pX11IMData = getX11InputMethodData(env, this); 1524 if (pX11IMData == NULL) { 1525 AWT_UNLOCK(); 1526 return jText; 1527 } 1528 1529 if (pX11IMData->current_ic) 1530 xText = XmbResetIC(pX11IMData->current_ic); 1531 else { 1532 /* 1533 * If there is no reference to the current XIC, try to reset both XICs. 1534 */ 1535 xText = XmbResetIC(pX11IMData->ic_active); 1536 /*it may also means that the real client component does 1537 not have focus -- has been deactivated... its xic should 1538 not have the focus, bug#4284651 showes reset XIC for htt 1539 may bring the focus back, so de-focus it again. 1540 */ 1541 setXICFocus(pX11IMData->ic_active, FALSE); 1542 if (pX11IMData->ic_active != pX11IMData->ic_passive) { 1543 char *tmpText = XmbResetIC(pX11IMData->ic_passive); 1544 setXICFocus(pX11IMData->ic_passive, FALSE); 1545 if (xText == (char *)NULL && tmpText) 1546 xText = tmpText; 1547 } 1548 1549 } 1550 if (xText != NULL) { 1551 jText = JNU_NewStringPlatform(env, (const char *)xText); 1552 XFree((void *)xText); 1553 } 1554 1555 AWT_UNLOCK(); 1556 return jText; 1557 } 1558 1559 /* 1560 * Class: sun_awt_X11InputMethod 1561 * Method: setCompositionEnabledNative 1562 * Signature: (ZJ)V 1563 * 1564 * This method tries to set the XNPreeditState attribute associated with the current 1565 * XIC to the passed in 'enable' state. 1566 * 1567 * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the 1568 * 'enable' state; Otherwise, if XSetICValues fails to set this attribute, 1569 * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this 1570 * method fails due to other reasons. 1571 * 1572 */ 1573 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_setCompositionEnabledNative 1574 (JNIEnv *env, jobject this, jboolean enable) 1575 { 1576 X11InputMethodData *pX11IMData; 1577 char * ret = NULL; 1578 1579 AWT_LOCK(); 1580 pX11IMData = getX11InputMethodData(env, this); 1581 1582 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { 1583 AWT_UNLOCK(); 1584 return JNI_FALSE; 1585 } 1586 1587 ret = XSetICValues(pX11IMData->current_ic, XNPreeditState, 1588 (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL); 1589 AWT_UNLOCK(); 1590 1591 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) { 1592 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); 1593 } 1594 1595 return (jboolean)(ret == 0); 1596 } 1597 1598 /* 1599 * Class: sun_awt_X11InputMethod 1600 * Method: isCompositionEnabledNative 1601 * Signature: (J)Z 1602 * 1603 * This method tries to get the XNPreeditState attribute associated with the current XIC. 1604 * 1605 * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if 1606 * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException 1607 * will be thrown. JNI_FALSE is returned if this method fails due to other reasons. 1608 * 1609 */ 1610 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_isCompositionEnabledNative 1611 (JNIEnv *env, jobject this) 1612 { 1613 X11InputMethodData *pX11IMData = NULL; 1614 char * ret = NULL; 1615 XIMPreeditState state; 1616 1617 AWT_LOCK(); 1618 pX11IMData = getX11InputMethodData(env, this); 1619 1620 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { 1621 AWT_UNLOCK(); 1622 return JNI_FALSE; 1623 } 1624 1625 ret = XGetICValues(pX11IMData->current_ic, XNPreeditState, &state, NULL); 1626 AWT_UNLOCK(); 1627 1628 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) { 1629 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); 1630 return JNI_FALSE; 1631 } 1632 1633 return (jboolean)(state == XIMPreeditEnable); 1634 } 1635 1636 JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow 1637 (JNIEnv *env, jobject this, jlong window) 1638 { 1639 #if defined(__linux__) || defined(MACOSX) 1640 AWT_LOCK(); 1641 adjustStatusWindow(window); 1642 AWT_UNLOCK(); 1643 #endif 1644 }