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