1 /* 2 * Copyright (c) 1997, 2005, 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 #ifdef XAWT 34 #include <sys/time.h> 35 #else /* !XAWT */ 36 #include <Xm/Xm.h> 37 #include <Xm/RowColumn.h> 38 #include <Xm/MwmUtil.h> 39 #include <Xm/MenuShell.h> 40 #endif /* XAWT */ 41 42 #include "awt.h" 43 #include "awt_p.h" 44 45 #include <sun_awt_X11InputMethod.h> 46 #ifdef XAWT 47 #include <sun_awt_X11_XComponentPeer.h> 48 #include <sun_awt_X11_XInputMethod.h> 49 50 #define XtWindow(w) (w) 51 #else /* !XAWT */ 52 #include <sun_awt_motif_MComponentPeer.h> 53 #include <sun_awt_motif_MInputMethod.h> 54 55 #define MCOMPONENTPEER_CLASS_NAME "sun/awt/motif/MComponentPeer" 56 #endif /* XAWT */ 57 58 #define THROW_OUT_OF_MEMORY_ERROR() \ 59 JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL) 60 #define SETARG(name, value) XtSetArg(args[argc], name, value); argc++ 61 62 struct X11InputMethodIDs { 63 jfieldID pData; 64 } x11InputMethodIDs; 65 66 static void PreeditStartCallback(XIC, XPointer, XPointer); 67 static void PreeditDoneCallback(XIC, XPointer, XPointer); 68 static void PreeditDrawCallback(XIC, XPointer, 69 XIMPreeditDrawCallbackStruct *); 70 static void PreeditCaretCallback(XIC, XPointer, 71 XIMPreeditCaretCallbackStruct *); 72 #ifdef __linux__ 73 static void StatusStartCallback(XIC, XPointer, XPointer); 74 static void StatusDoneCallback(XIC, XPointer, XPointer); 75 static void StatusDrawCallback(XIC, XPointer, 76 XIMStatusDrawCallbackStruct *); 77 #endif 78 79 #define ROOT_WINDOW_STYLES (XIMPreeditNothing | XIMStatusNothing) 80 #define NO_STYLES (XIMPreeditNone | XIMStatusNone) 81 82 #define PreeditStartIndex 0 83 #define PreeditDoneIndex 1 84 #define PreeditDrawIndex 2 85 #define PreeditCaretIndex 3 86 #ifdef __linux__ 87 #define StatusStartIndex 4 88 #define StatusDoneIndex 5 89 #define StatusDrawIndex 6 90 #define NCALLBACKS 7 91 #else 92 #define NCALLBACKS 4 93 #endif 94 95 /* 96 * Callback function pointers: the order has to match the *Index 97 * values above. 98 */ 99 static XIMProc callback_funcs[NCALLBACKS] = { 100 (XIMProc)PreeditStartCallback, 101 (XIMProc)PreeditDoneCallback, 102 (XIMProc)PreeditDrawCallback, 103 (XIMProc)PreeditCaretCallback, 104 #ifdef __linux__ 105 (XIMProc)StatusStartCallback, 106 (XIMProc)StatusDoneCallback, 107 (XIMProc)StatusDrawCallback, 108 #endif 109 }; 110 111 #ifdef __linux__ 112 #define MAX_STATUS_LEN 100 113 typedef struct { 114 Window w; /*status window id */ 115 Window root; /*the root window id */ 116 #ifdef XAWT 117 Window parent; /*parent shell window */ 118 #else 119 Widget parent; /*parent shell window */ 120 #endif 121 int x, y; /*parent's upperleft position */ 122 int width, height; /*parent's width, height */ 123 GC lightGC; /*gc for light border */ 124 GC dimGC; /*gc for dim border */ 125 GC bgGC; /*normal painting */ 126 GC fgGC; /*normal painting */ 127 int statusW, statusH; /*status window's w, h */ 128 int rootW, rootH; /*root window's w, h */ 129 int bWidth; /*border width */ 130 char status[MAX_STATUS_LEN]; /*status text */ 131 XFontSet fontset; /*fontset for drawing */ 132 int off_x, off_y; 133 Bool on; /*if the status window on*/ 134 } StatusWindow; 135 #endif 136 137 /* 138 * X11InputMethodData keeps per X11InputMethod instance information. A pointer 139 * to this data structure is kept in an X11InputMethod object (pData). 140 */ 141 typedef struct _X11InputMethodData { 142 XIC current_ic; /* current X Input Context */ 143 XIC ic_active; /* X Input Context for active clients */ 144 XIC ic_passive; /* X Input Context for passive clients */ 145 XIMCallback *callbacks; /* callback parameters */ 146 #ifndef XAWT 147 jobject peer; /* MComponentPeer of client Window */ 148 #endif /* XAWT */ 149 jobject x11inputmethod; /* global ref to X11InputMethod instance */ 150 /* associated with the XIC */ 151 #ifdef __linux__ 152 StatusWindow *statusWindow; /* our own status window */ 153 #else 154 #ifndef XAWT 155 Widget statusWidget; /* IM status window widget */ 156 #endif /* XAWT */ 157 #endif 158 char *lookup_buf; /* buffer used for XmbLookupString */ 159 int lookup_buf_len; /* lookup buffer size in bytes */ 160 } X11InputMethodData; 161 162 /* 163 * When XIC is created, a global reference is created for 164 * sun.awt.X11InputMethod object so that it could be used by the XIM callback 165 * functions. This could be a dangerous thing to do when the original 166 * X11InputMethod object is garbage collected and as a result, 167 * destroyX11InputMethodData is called to delete the global reference. 168 * If any XIM callback function still holds and uses the "already deleted" 169 * global reference, disaster is going to happen. So we have to maintain 170 * a list for these global references which is consulted first when the 171 * callback functions or any function tries to use "currentX11InputMethodObject" 172 * which always refers to the global reference try to use it. 173 * 174 */ 175 typedef struct _X11InputMethodGRefNode { 176 jobject inputMethodGRef; 177 struct _X11InputMethodGRefNode* next; 178 } X11InputMethodGRefNode; 179 180 X11InputMethodGRefNode *x11InputMethodGRefListHead = NULL; 181 182 /* reference to the current X11InputMethod instance, it is always 183 point to the global reference to the X11InputMethodObject since 184 it could be referenced by different threads. */ 185 jobject currentX11InputMethodInstance = NULL; 186 187 Window currentFocusWindow = 0; /* current window that has focus for input 188 method. (the best place to put this 189 information should be 190 currentX11InputMethodInstance's pData) */ 191 static XIM X11im = NULL; 192 Display * dpy = NULL; 193 194 #define GetJNIEnv() (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2) 195 196 #ifndef XAWT 197 static jobject mcompClass = NULL; 198 static jobject awteventClass = NULL; 199 static jfieldID mcompPDataID = NULL; 200 #endif /* XAWT */ 201 202 static void DestroyXIMCallback(XIM, XPointer, XPointer); 203 static void OpenXIMCallback(Display *, XPointer, XPointer); 204 /* Solaris XIM Extention */ 205 #define XNCommitStringCallback "commitStringCallback" 206 static void CommitStringCallback(XIC, XPointer, XPointer); 207 208 static X11InputMethodData * getX11InputMethodData(JNIEnv *, jobject); 209 static void setX11InputMethodData(JNIEnv *, jobject, X11InputMethodData *); 210 static void destroyX11InputMethodData(JNIEnv *, X11InputMethodData *); 211 static void freeX11InputMethodData(JNIEnv *, X11InputMethodData *); 212 213 #ifdef __solaris__ 214 /* Prototype for this function is missing in Solaris X11R6 Xlib.h */ 215 extern char *XSetIMValues( 216 #if NeedVarargsPrototypes 217 XIM /* im */, ... 218 #endif 219 ); 220 #endif 221 222 #ifdef XAWT_HACK 223 /* 224 * This function is stolen from /src/solaris/hpi/src/system_md.c 225 * It is used in setting the time in Java-level InputEvents 226 */ 227 jlong 228 awt_util_nowMillisUTC() 229 { 230 struct timeval t; 231 gettimeofday(&t, NULL); 232 return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000); 233 } 234 #endif /* XAWT_HACK */ 235 236 /* 237 * Converts the wchar_t string to a multi-byte string calling wcstombs(). A 238 * buffer is allocated by malloc() to store the multi-byte string. NULL is 239 * returned if the given wchar_t string pointer is NULL or buffer allocation is 240 * failed. 241 */ 242 static char * 243 wcstombsdmp(wchar_t *wcs, int len) 244 { 245 size_t n; 246 char *mbs; 247 248 if (wcs == NULL) 249 return NULL; 250 251 n = len*MB_CUR_MAX + 1; 252 253 mbs = (char *) malloc(n * sizeof(char)); 254 if (mbs == NULL) { 255 THROW_OUT_OF_MEMORY_ERROR(); 256 return NULL; 257 } 258 259 /* TODO: check return values... Handle invalid characters properly... */ 260 if (wcstombs(mbs, wcs, n) == (size_t)-1) 261 return NULL; 262 263 return mbs; 264 } 265 266 #ifndef XAWT 267 /* 268 * Find a class for the given class name and return a global reference to the 269 * class. 270 */ 271 static jobject 272 findClass(const char *className) 273 { 274 JNIEnv *env = GetJNIEnv(); 275 jclass classClass; 276 jobject objectClass; 277 278 classClass = (*env)->FindClass(env, className); 279 objectClass = (*env)->NewGlobalRef(env,classClass); 280 281 if (JNU_IsNull(env, objectClass)) { 282 JNU_ThrowClassNotFoundException(env, className); 283 } 284 return objectClass; 285 } 286 #endif /* XAWT */ 287 288 /* 289 * Returns True if the global reference is still in the list, 290 * otherwise False. 291 */ 292 static Bool isX11InputMethodGRefInList(jobject imGRef) { 293 X11InputMethodGRefNode *pX11InputMethodGRef = x11InputMethodGRefListHead; 294 295 if (imGRef == NULL) { 296 return False; 297 } 298 299 while (pX11InputMethodGRef != NULL) { 300 if (pX11InputMethodGRef->inputMethodGRef == imGRef) { 301 return True; 302 } 303 pX11InputMethodGRef = pX11InputMethodGRef->next; 304 } 305 306 return False; 307 } 308 309 /* 310 * Add the new created global reference to the list. 311 */ 312 static void addToX11InputMethodGRefList(jobject newX11InputMethodGRef) { 313 X11InputMethodGRefNode *newNode = NULL; 314 315 if (newX11InputMethodGRef == NULL || 316 isX11InputMethodGRefInList(newX11InputMethodGRef)) { 317 return; 318 } 319 320 newNode = (X11InputMethodGRefNode *)malloc(sizeof(X11InputMethodGRefNode)); 321 322 if (newNode == NULL) { 323 return; 324 } else { 325 newNode->inputMethodGRef = newX11InputMethodGRef; 326 newNode->next = x11InputMethodGRefListHead; 327 x11InputMethodGRefListHead = newNode; 328 } 329 } 330 331 /* 332 * Remove the global reference from the list. 333 */ 334 static void removeX11InputMethodGRefFromList(jobject x11InputMethodGRef) { 335 X11InputMethodGRefNode *pX11InputMethodGRef = NULL; 336 X11InputMethodGRefNode *cX11InputMethodGRef = x11InputMethodGRefListHead; 337 338 if (x11InputMethodGRefListHead == NULL || 339 x11InputMethodGRef == NULL) { 340 return; 341 } 342 343 /* cX11InputMethodGRef always refers to the current node while 344 pX11InputMethodGRef refers to the previous node. 345 */ 346 while (cX11InputMethodGRef != NULL) { 347 if (cX11InputMethodGRef->inputMethodGRef == x11InputMethodGRef) { 348 break; 349 } 350 pX11InputMethodGRef = cX11InputMethodGRef; 351 cX11InputMethodGRef = cX11InputMethodGRef->next; 352 } 353 354 if (cX11InputMethodGRef == NULL) { 355 return; /* Not found. */ 356 } 357 358 if (cX11InputMethodGRef == x11InputMethodGRefListHead) { 359 x11InputMethodGRefListHead = x11InputMethodGRefListHead->next; 360 } else { 361 pX11InputMethodGRef->next = cX11InputMethodGRef->next; 362 } 363 free(cX11InputMethodGRef); 364 365 return; 366 } 367 368 369 static X11InputMethodData * getX11InputMethodData(JNIEnv * env, jobject imInstance) { 370 X11InputMethodData *pX11IMData = 371 (X11InputMethodData *)JNU_GetLongFieldAsPtr(env, imInstance, x11InputMethodIDs.pData); 372 373 /* 374 * In case the XIM server was killed somehow, reset X11InputMethodData. 375 */ 376 if (X11im == NULL && pX11IMData != NULL) { 377 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, 378 "flushText", 379 "()V"); 380 /* IMPORTANT: 381 The order of the following calls is critical since "imInstance" may 382 point to the global reference itself, if "freeX11InputMethodData" is called 383 first, the global reference will be destroyed and "setX11InputMethodData" 384 will in fact fail silently. So pX11IMData will not be set to NULL. 385 This could make the original java object refers to a deleted pX11IMData 386 object. 387 */ 388 setX11InputMethodData(env, imInstance, NULL); 389 freeX11InputMethodData(env, pX11IMData); 390 pX11IMData = NULL; 391 } 392 393 return pX11IMData; 394 } 395 396 static void setX11InputMethodData(JNIEnv * env, jobject imInstance, X11InputMethodData *pX11IMData) { 397 JNU_SetLongFieldFromPtr(env, imInstance, x11InputMethodIDs.pData, pX11IMData); 398 } 399 400 /* this function should be called within AWT_LOCK() */ 401 static void 402 destroyX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData) 403 { 404 /* 405 * Destroy XICs 406 */ 407 if (pX11IMData == NULL) { 408 return; 409 } 410 411 if (pX11IMData->ic_active != (XIC)0) { 412 XUnsetICFocus(pX11IMData->ic_active); 413 XDestroyIC(pX11IMData->ic_active); 414 if (pX11IMData->ic_active != pX11IMData->ic_passive) { 415 if (pX11IMData->ic_passive != (XIC)0) { 416 XUnsetICFocus(pX11IMData->ic_passive); 417 XDestroyIC(pX11IMData->ic_passive); 418 } 419 pX11IMData->ic_passive = (XIC)0; 420 pX11IMData->current_ic = (XIC)0; 421 } 422 } 423 424 freeX11InputMethodData(env, pX11IMData); 425 } 426 427 static void 428 freeX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData) 429 { 430 #ifdef __linux__ 431 if (pX11IMData->statusWindow != NULL){ 432 StatusWindow *sw = pX11IMData->statusWindow; 433 XFreeGC(awt_display, sw->lightGC); 434 XFreeGC(awt_display, sw->dimGC); 435 XFreeGC(awt_display, sw->bgGC); 436 XFreeGC(awt_display, sw->fgGC); 437 if (sw->fontset != NULL) { 438 XFreeFontSet(awt_display, sw->fontset); 439 } 440 XDestroyWindow(awt_display, sw->w); 441 free((void*)sw); 442 } 443 #endif 444 445 if (pX11IMData->callbacks) 446 free((void *)pX11IMData->callbacks); 447 448 if (env) { 449 #ifndef XAWT 450 (*env)->DeleteGlobalRef(env, pX11IMData->peer); 451 #endif /* XAWT */ 452 /* Remove the global reference from the list, so that 453 the callback function or whoever refers to it could know. 454 */ 455 removeX11InputMethodGRefFromList(pX11IMData->x11inputmethod); 456 (*env)->DeleteGlobalRef(env, pX11IMData->x11inputmethod); 457 } 458 459 if (pX11IMData->lookup_buf) { 460 free((void *)pX11IMData->lookup_buf); 461 } 462 463 free((void *)pX11IMData); 464 } 465 466 /* 467 * Sets or unsets the focus to the given XIC. 468 */ 469 static void 470 setXICFocus(XIC ic, unsigned short req) 471 { 472 if (ic == NULL) { 473 (void)fprintf(stderr, "Couldn't find X Input Context\n"); 474 return; 475 } 476 if (req == 1) 477 XSetICFocus(ic); 478 else 479 XUnsetICFocus(ic); 480 } 481 482 /* 483 * Sets the focus window to the given XIC. 484 */ 485 static void 486 setXICWindowFocus(XIC ic, Window w) 487 { 488 if (ic == NULL) { 489 (void)fprintf(stderr, "Couldn't find X Input Context\n"); 490 return; 491 } 492 (void) XSetICValues(ic, XNFocusWindow, w, NULL); 493 } 494 495 /* 496 * Invokes XmbLookupString() to get something from the XIM. It invokes 497 * X11InputMethod.dispatchCommittedText() if XmbLookupString() returns 498 * committed text. This function is called from handleKeyEvent in canvas.c and 499 * it's under the Motif event loop thread context. 500 * 501 * Buffer usage: There is a bug in XFree86-4.3.0 XmbLookupString implementation, 502 * where it never returns XBufferOverflow. We need to allocate the initial lookup buffer 503 * big enough, so that the possibility that user encounters this problem is relatively 504 * small. When this bug gets fixed, we can make the initial buffer size smaller. 505 * Note that XmbLookupString() sometimes produces a non-null-terminated string. 506 * 507 * Returns True when there is a keysym value to be handled. 508 */ 509 #define INITIAL_LOOKUP_BUF_SIZE 512 510 511 Bool 512 awt_x11inputmethod_lookupString(XKeyPressedEvent *event, KeySym *keysymp) 513 { 514 JNIEnv *env = GetJNIEnv(); 515 X11InputMethodData *pX11IMData = NULL; 516 KeySym keysym = NoSymbol; 517 Status status; 518 int mblen; 519 jstring javastr; 520 XIC ic; 521 Bool result = True; 522 static Bool composing = False; 523 524 /* 525 printf("lookupString: entering...\n"); 526 */ 527 528 if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) { 529 currentX11InputMethodInstance = NULL; 530 return False; 531 } 532 533 pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance); 534 535 if (pX11IMData == NULL) { 536 #ifdef __linux__ 537 return False; 538 #else 539 return result; 540 #endif 541 } 542 543 if ((ic = pX11IMData->current_ic) == (XIC)0){ 544 #ifdef __linux__ 545 return False; 546 #else 547 return result; 548 #endif 549 } 550 551 /* allocate the lookup buffer at the first invocation */ 552 if (pX11IMData->lookup_buf_len == 0) { 553 pX11IMData->lookup_buf = (char *)malloc(INITIAL_LOOKUP_BUF_SIZE); 554 if (pX11IMData->lookup_buf == NULL) { 555 THROW_OUT_OF_MEMORY_ERROR(); 556 return result; 557 } 558 pX11IMData->lookup_buf_len = INITIAL_LOOKUP_BUF_SIZE; 559 } 560 561 mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf, 562 pX11IMData->lookup_buf_len - 1, &keysym, &status); 563 564 /* 565 * In case of overflow, a buffer is allocated and it retries 566 * XmbLookupString(). 567 */ 568 if (status == XBufferOverflow) { 569 free((void *)pX11IMData->lookup_buf); 570 pX11IMData->lookup_buf_len = 0; 571 pX11IMData->lookup_buf = (char *)malloc(mblen + 1); 572 if (pX11IMData->lookup_buf == NULL) { 573 THROW_OUT_OF_MEMORY_ERROR(); 574 return result; 575 } 576 pX11IMData->lookup_buf_len = mblen + 1; 577 mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf, 578 pX11IMData->lookup_buf_len - 1, &keysym, &status); 579 } 580 pX11IMData->lookup_buf[mblen] = 0; 581 582 /* Get keysym without taking modifiers into account first to map 583 * to AWT keyCode table. 584 */ 585 #ifndef XAWT 586 if (((event->state & ShiftMask) || 587 (event->state & LockMask)) && 588 keysym >= 'A' && keysym <= 'Z') 589 { 590 keysym = XLookupKeysym(event, 0); 591 } 592 #endif 593 594 switch (status) { 595 case XLookupBoth: 596 if (!composing) { 597 #ifdef XAWT 598 if (event->keycode != 0) { 599 #else 600 if (keysym < 128 || ((keysym & 0xff00) == 0xff00)) { 601 #endif 602 *keysymp = keysym; 603 result = False; 604 break; 605 } 606 } 607 composing = False; 608 /*FALLTHRU*/ 609 case XLookupChars: 610 /* 611 printf("lookupString: status=XLookupChars, type=%d, state=%x, keycode=%x, keysym=%x\n", 612 event->type, event->state, event->keycode, keysym); 613 */ 614 javastr = JNU_NewStringPlatform(env, (const char *)pX11IMData->lookup_buf); 615 if (javastr != NULL) { 616 JNU_CallMethodByName(env, NULL, 617 currentX11InputMethodInstance, 618 "dispatchCommittedText", 619 "(Ljava/lang/String;J)V", 620 javastr, 621 #ifndef XAWT_HACK 622 awt_util_nowMillisUTC_offset(event->time)); 623 #else 624 event->time); 625 #endif 626 } 627 break; 628 629 case XLookupKeySym: 630 /* 631 printf("lookupString: status=XLookupKeySym, type=%d, state=%x, keycode=%x, keysym=%x\n", 632 event->type, event->state, event->keycode, keysym); 633 */ 634 if (keysym == XK_Multi_key) 635 composing = True; 636 if (! composing) { 637 *keysymp = keysym; 638 result = False; 639 } 640 break; 641 642 case XLookupNone: 643 /* 644 printf("lookupString: status=XLookupNone, type=%d, state=%x, keycode=%x, keysym=%x\n", 645 event->type, event->state, event->keycode, keysym); 646 */ 647 break; 648 } 649 650 return result; 651 } 652 653 #ifdef __linux__ 654 static StatusWindow *createStatusWindow( 655 #ifdef XAWT 656 Window parent) { 657 #else 658 Widget parent) { 659 #endif 660 StatusWindow *statusWindow; 661 XSetWindowAttributes attrib; 662 unsigned long attribmask; 663 Window containerWindow; 664 Window status; 665 Window child; 666 XWindowAttributes xwa; 667 XWindowAttributes xxwa; 668 /* Variable for XCreateFontSet()*/ 669 char **mclr; 670 int mccr = 0; 671 char *dsr; 672 Pixel bg, fg, light, dim; 673 int x, y, w, h, bw, depth, off_x, off_y, xx, yy; 674 XGCValues values; 675 unsigned long valuemask = 0; /*ignore XGCvalue and use defaults*/ 676 int screen = 0; 677 int i; 678 AwtGraphicsConfigDataPtr adata; 679 extern int awt_numScreens; 680 /*hardcode the size right now, should get the size base on font*/ 681 int width=80, height=22; 682 Window rootWindow; 683 Window *ignoreWindowPtr; 684 unsigned int ignoreUnit; 685 686 #ifdef XAWT 687 XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth); 688 #else 689 while (!XtIsShell(parent)){ 690 parent = XtParent(parent); 691 } 692 #endif 693 694 attrib.override_redirect = True; 695 attribmask = CWOverrideRedirect; 696 for (i = 0; i < awt_numScreens; i++) { 697 #ifdef XAWT 698 if (RootWindow(dpy, i) == rootWindow) { 699 #else 700 if (ScreenOfDisplay(dpy, i) == XtScreen(parent)) { 701 #endif 702 screen = i; 703 break; 704 } 705 } 706 adata = getDefaultConfig(screen); 707 bg = adata->AwtColorMatch(255, 255, 255, adata); 708 fg = adata->AwtColorMatch(0, 0, 0, adata); 709 light = adata->AwtColorMatch(195, 195, 195, adata); 710 dim = adata->AwtColorMatch(128, 128, 128, adata); 711 712 XGetWindowAttributes(dpy, XtWindow(parent), &xwa); 713 bw = 2; /*xwa.border_width does not have the correct value*/ 714 715 /*compare the size difference between parent container 716 and shell widget, the diff should be the border frame 717 and title bar height (?)*/ 718 719 XQueryTree( dpy, 720 XtWindow(parent), 721 &rootWindow, 722 &containerWindow, 723 &ignoreWindowPtr, 724 &ignoreUnit); 725 XGetWindowAttributes(dpy, containerWindow, &xxwa); 726 727 off_x = (xxwa.width - xwa.width) / 2; 728 off_y = xxwa.height - xwa.height - off_x; /*it's magic:-) */ 729 730 /*get the size of root window*/ 731 XGetWindowAttributes(dpy, rootWindow, &xxwa); 732 733 XTranslateCoordinates(dpy, 734 XtWindow(parent), xwa.root, 735 xwa.x, xwa.y, 736 &x, &y, 737 &child); 738 xx = x - off_x; 739 yy = y + xwa.height - off_y; 740 if (xx < 0 ){ 741 xx = 0; 742 } 743 if (xx + width > xxwa.width){ 744 xx = xxwa.width - width; 745 } 746 if (yy + height > xxwa.height){ 747 yy = xxwa.height - height; 748 } 749 750 status = XCreateWindow(dpy, 751 xwa.root, 752 xx, yy, 753 width, height, 754 0, 755 xwa.depth, 756 InputOutput, 757 adata->awt_visInfo.visual, 758 attribmask, &attrib); 759 XSelectInput(dpy, status, 760 ExposureMask | StructureNotifyMask | EnterWindowMask | 761 LeaveWindowMask | VisibilityChangeMask); 762 statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow)); 763 if (statusWindow == NULL){ 764 THROW_OUT_OF_MEMORY_ERROR(); 765 return NULL; 766 } 767 statusWindow->w = status; 768 //12-point font 769 statusWindow->fontset = XCreateFontSet(dpy, 770 "-*-*-medium-r-normal-*-*-120-*-*-*-*", 771 &mclr, &mccr, &dsr); 772 /* In case we didn't find the font set, release the list of missing characters */ 773 if (mccr > 0) { 774 XFreeStringList(mclr); 775 } 776 statusWindow->parent = parent; 777 statusWindow->on = False; 778 statusWindow->x = x; 779 statusWindow->y = y; 780 statusWindow->width = xwa.width; 781 statusWindow->height = xwa.height; 782 statusWindow->off_x = off_x; 783 statusWindow->off_y = off_y; 784 statusWindow->bWidth = bw; 785 statusWindow->statusH = height; 786 statusWindow->statusW = width; 787 statusWindow->rootH = xxwa.height; 788 statusWindow->rootW = xxwa.width; 789 statusWindow->lightGC = XCreateGC(dpy, status, valuemask, &values); 790 XSetForeground(dpy, statusWindow->lightGC, light); 791 statusWindow->dimGC = XCreateGC(dpy, status, valuemask, &values); 792 XSetForeground(dpy, statusWindow->dimGC, dim); 793 statusWindow->fgGC = XCreateGC(dpy, status, valuemask, &values); 794 XSetForeground(dpy, statusWindow->fgGC, fg); 795 statusWindow->bgGC = XCreateGC(dpy, status, valuemask, &values); 796 XSetForeground(dpy, statusWindow->bgGC, bg); 797 return statusWindow; 798 } 799 800 /* This method is to turn off or turn on the status window. */ 801 static void onoffStatusWindow(X11InputMethodData* pX11IMData, 802 #ifdef XAWT 803 Window parent, 804 #else 805 Widget parent, 806 #endif 807 Bool ON){ 808 XWindowAttributes xwa; 809 Window child; 810 int x, y; 811 StatusWindow *statusWindow = NULL; 812 813 if (NULL == currentX11InputMethodInstance || 814 NULL == pX11IMData || 815 NULL == (statusWindow = pX11IMData->statusWindow)){ 816 return; 817 } 818 819 if (ON == False){ 820 XUnmapWindow(dpy, statusWindow->w); 821 statusWindow->on = False; 822 return; 823 } 824 #ifdef XAWT 825 parent = JNU_CallMethodByName(GetJNIEnv(), NULL, pX11IMData->x11inputmethod, 826 "getCurrentParentWindow", 827 "()J").j; 828 #else 829 while (!XtIsShell(parent)){ 830 parent = XtParent(parent); 831 } 832 #endif 833 if (statusWindow->parent != parent){ 834 statusWindow->parent = parent; 835 } 836 XGetWindowAttributes(dpy, XtWindow(parent), &xwa); 837 XTranslateCoordinates(dpy, 838 XtWindow(parent), xwa.root, 839 xwa.x, xwa.y, 840 &x, &y, 841 &child); 842 if (statusWindow->x != x 843 || statusWindow->y != y 844 || statusWindow->height != xwa.height){ 845 statusWindow->x = x; 846 statusWindow->y = y; 847 statusWindow->height = xwa.height; 848 x = statusWindow->x - statusWindow->off_x; 849 y = statusWindow->y + statusWindow->height - statusWindow->off_y; 850 if (x < 0 ){ 851 x = 0; 852 } 853 if (x + statusWindow->statusW > statusWindow->rootW){ 854 x = statusWindow->rootW - statusWindow->statusW; 855 } 856 if (y + statusWindow->statusH > statusWindow->rootH){ 857 y = statusWindow->rootH - statusWindow->statusH; 858 } 859 XMoveWindow(dpy, statusWindow->w, x, y); 860 } 861 statusWindow->on = True; 862 XMapWindow(dpy, statusWindow->w); 863 } 864 865 void paintStatusWindow(StatusWindow *statusWindow){ 866 Window win = statusWindow->w; 867 GC lightgc = statusWindow->lightGC; 868 GC dimgc = statusWindow->dimGC; 869 GC bggc = statusWindow->bgGC; 870 GC fggc = statusWindow->fgGC; 871 872 int width = statusWindow->statusW; 873 int height = statusWindow->statusH; 874 int bwidth = statusWindow->bWidth; 875 XFillRectangle(dpy, win, bggc, 0, 0, width, height); 876 /* draw border */ 877 XDrawLine(dpy, win, fggc, 0, 0, width, 0); 878 XDrawLine(dpy, win, fggc, 0, height-1, width-1, height-1); 879 XDrawLine(dpy, win, fggc, 0, 0, 0, height-1); 880 XDrawLine(dpy, win, fggc, width-1, 0, width-1, height-1); 881 882 XDrawLine(dpy, win, lightgc, 1, 1, width-bwidth, 1); 883 XDrawLine(dpy, win, lightgc, 1, 1, 1, height-2); 884 XDrawLine(dpy, win, lightgc, 1, height-2, width-bwidth, height-2); 885 XDrawLine(dpy, win, lightgc, width-bwidth-1, 1, width-bwidth-1, height-2); 886 887 XDrawLine(dpy, win, dimgc, 2, 2, 2, height-3); 888 XDrawLine(dpy, win, dimgc, 2, height-3, width-bwidth-1, height-3); 889 XDrawLine(dpy, win, dimgc, 2, 2, width-bwidth-2, 2); 890 XDrawLine(dpy, win, dimgc, width-bwidth, 2, width-bwidth, height-3); 891 if (statusWindow->fontset){ 892 XmbDrawString(dpy, win, statusWindow->fontset, fggc, 893 bwidth + 2, height - bwidth - 4, 894 statusWindow->status, 895 strlen(statusWindow->status)); 896 } 897 else{ 898 /*too bad we failed to create a fontset for this locale*/ 899 XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4, 900 "[InputMethod ON]", strlen("[InputMethod ON]")); 901 } 902 } 903 904 void statusWindowEventHandler(XEvent event){ 905 JNIEnv *env = GetJNIEnv(); 906 X11InputMethodData *pX11IMData = NULL; 907 StatusWindow *statusWindow; 908 909 if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) { 910 currentX11InputMethodInstance = NULL; 911 return; 912 } 913 914 if (NULL == currentX11InputMethodInstance 915 || NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance)) 916 || NULL == (statusWindow = pX11IMData->statusWindow) 917 || statusWindow->w != event.xany.window){ 918 return; 919 } 920 921 switch (event.type){ 922 case Expose: 923 paintStatusWindow(statusWindow); 924 break; 925 case MapNotify: 926 case ConfigureNotify: 927 { 928 /*need to reset the stackMode...*/ 929 XWindowChanges xwc; 930 int value_make = CWStackMode; 931 xwc.stack_mode = TopIf; 932 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); 933 } 934 break; 935 /* 936 case UnmapNotify: 937 case VisibilityNotify: 938 break; 939 */ 940 default: 941 break; 942 } 943 } 944 945 #ifdef XAWT 946 static void adjustStatusWindow(Window shell){ 947 #else 948 void adjustStatusWindow(Widget shell){ 949 #endif 950 JNIEnv *env = GetJNIEnv(); 951 X11InputMethodData *pX11IMData = NULL; 952 StatusWindow *statusWindow; 953 954 if (NULL == currentX11InputMethodInstance 955 || !isX11InputMethodGRefInList(currentX11InputMethodInstance) 956 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance)) 957 || NULL == (statusWindow = pX11IMData->statusWindow) 958 || !statusWindow->on) { 959 return; 960 } 961 #ifdef XAWT 962 { 963 #else 964 if (statusWindow->parent == shell) { 965 #endif 966 XWindowAttributes xwa; 967 int x, y; 968 Window child; 969 XGetWindowAttributes(dpy, XtWindow(shell), &xwa); 970 XTranslateCoordinates(dpy, 971 XtWindow(shell), xwa.root, 972 xwa.x, xwa.y, 973 &x, &y, 974 &child); 975 if (statusWindow->x != x 976 || statusWindow->y != y 977 || statusWindow->height != xwa.height){ 978 statusWindow->x = x; 979 statusWindow->y = y; 980 statusWindow->height = xwa.height; 981 982 x = statusWindow->x - statusWindow->off_x; 983 y = statusWindow->y + statusWindow->height - statusWindow->off_y; 984 if (x < 0 ){ 985 x = 0; 986 } 987 if (x + statusWindow->statusW > statusWindow->rootW){ 988 x = statusWindow->rootW - statusWindow->statusW; 989 } 990 if (y + statusWindow->statusH > statusWindow->rootH){ 991 y = statusWindow->rootH - statusWindow->statusH; 992 } 993 XMoveWindow(dpy, statusWindow->w, x, y); 994 } 995 } 996 } 997 #endif /*__linux__*/ 998 /* 999 * Creates two XICs, one for active clients and the other for passive 1000 * clients. All information on those XICs are stored in the 1001 * X11InputMethodData given by the pX11IMData parameter. 1002 * 1003 * For active clients: Try to use preedit callback to support 1004 * on-the-spot. If tc is not null, the XIC to be created will 1005 * share the Status Area with Motif widgets (TextComponents). If the 1006 * preferable styles can't be used, fallback to root-window styles. If 1007 * root-window styles failed, fallback to None styles. 1008 * 1009 * For passive clients: Try to use root-window styles. If failed, 1010 * fallback to None styles. 1011 */ 1012 static Bool 1013 #ifdef XAWT 1014 createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w) 1015 #else /* !XAWT */ 1016 createXIC(Widget w, X11InputMethodData *pX11IMData, 1017 jobject tc, jobject peer) 1018 #endif /* XAWT */ 1019 { 1020 XIC active_ic, passive_ic; 1021 XVaNestedList preedit = NULL; 1022 XVaNestedList status = NULL; 1023 XIMStyle on_the_spot_styles = XIMPreeditCallbacks, 1024 active_styles = 0, 1025 passive_styles = 0, 1026 no_styles = 0; 1027 XIMCallback *callbacks; 1028 unsigned short i; 1029 XIMStyles *im_styles; 1030 char *ret = NULL; 1031 1032 if (X11im == NULL) { 1033 return False; 1034 } 1035 #ifdef XAWT 1036 if (w == NULL) { 1037 return False; 1038 } 1039 #else /* !XAWT */ 1040 /* 1041 * If the parent window has one or more TextComponents, the status 1042 * area of Motif will be shared with the created XIC. Otherwise, 1043 * root-window style status is used. 1044 */ 1045 #endif /* XAWT */ 1046 1047 ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL); 1048 1049 if (ret != NULL) { 1050 jio_fprintf(stderr,"XGetIMValues: %s\n",ret); 1051 return FALSE ; 1052 } 1053 1054 #ifdef __linux__ 1055 on_the_spot_styles |= XIMStatusNothing; 1056 1057 /*kinput does not support XIMPreeditCallbacks and XIMStatusArea 1058 at the same time, so use StatusCallback to draw the status 1059 ourself 1060 */ 1061 for (i = 0; i < im_styles->count_styles; i++) { 1062 if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) { 1063 on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks); 1064 break; 1065 } 1066 } 1067 #else /*! __linux__ */ 1068 #ifdef XAWT 1069 on_the_spot_styles |= XIMStatusNothing; 1070 #else /* !XAWT */ 1071 /* 1072 * If the parent window has one or more TextComponents, the status 1073 * area of Motif will be shared with the created XIC. Otherwise, 1074 * root-window style status is used. 1075 */ 1076 if (tc != NULL){ 1077 XVaNestedList status = NULL; 1078 status = awt_motif_getXICStatusAreaList(w, tc); 1079 if (status != NULL){ 1080 on_the_spot_styles |= XIMStatusArea; 1081 XFree(status); 1082 } 1083 else 1084 on_the_spot_styles |= XIMStatusNothing; 1085 } 1086 else 1087 on_the_spot_styles |= XIMStatusNothing; 1088 1089 #endif /* XAWT */ 1090 #endif /* __linux__ */ 1091 1092 for (i = 0; i < im_styles->count_styles; i++) { 1093 active_styles |= im_styles->supported_styles[i] & on_the_spot_styles; 1094 passive_styles |= im_styles->supported_styles[i] & ROOT_WINDOW_STYLES; 1095 no_styles |= im_styles->supported_styles[i] & NO_STYLES; 1096 } 1097 1098 XFree(im_styles); 1099 1100 if (active_styles != on_the_spot_styles) { 1101 if (passive_styles == ROOT_WINDOW_STYLES) 1102 active_styles = passive_styles; 1103 else { 1104 if (no_styles == NO_STYLES) 1105 active_styles = passive_styles = NO_STYLES; 1106 else 1107 active_styles = passive_styles = 0; 1108 } 1109 } else { 1110 if (passive_styles != ROOT_WINDOW_STYLES) { 1111 if (no_styles == NO_STYLES) 1112 active_styles = passive_styles = NO_STYLES; 1113 else 1114 active_styles = passive_styles = 0; 1115 } 1116 } 1117 1118 if (active_styles == on_the_spot_styles) { 1119 callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS); 1120 if (callbacks == (XIMCallback *)NULL) 1121 return False; 1122 pX11IMData->callbacks = callbacks; 1123 1124 for (i = 0; i < NCALLBACKS; i++, callbacks++) { 1125 callbacks->client_data = (XPointer) pX11IMData->x11inputmethod; 1126 callbacks->callback = callback_funcs[i]; 1127 } 1128 1129 callbacks = pX11IMData->callbacks; 1130 preedit = (XVaNestedList)XVaCreateNestedList(0, 1131 XNPreeditStartCallback, &callbacks[PreeditStartIndex], 1132 XNPreeditDoneCallback, &callbacks[PreeditDoneIndex], 1133 XNPreeditDrawCallback, &callbacks[PreeditDrawIndex], 1134 XNPreeditCaretCallback, &callbacks[PreeditCaretIndex], 1135 NULL); 1136 if (preedit == (XVaNestedList)NULL) 1137 goto err; 1138 #ifdef __linux__ 1139 /*always try XIMStatusCallbacks for active client...*/ 1140 { 1141 status = (XVaNestedList)XVaCreateNestedList(0, 1142 XNStatusStartCallback, &callbacks[StatusStartIndex], 1143 XNStatusDoneCallback, &callbacks[StatusDoneIndex], 1144 XNStatusDrawCallback, &callbacks[StatusDrawIndex], 1145 NULL); 1146 1147 if (status == NULL) 1148 goto err; 1149 pX11IMData->statusWindow = createStatusWindow(w); 1150 pX11IMData->ic_active = XCreateIC(X11im, 1151 XNClientWindow, XtWindow(w), 1152 XNFocusWindow, XtWindow(w), 1153 XNInputStyle, active_styles, 1154 XNPreeditAttributes, preedit, 1155 XNStatusAttributes, status, 1156 NULL); 1157 XFree((void *)status); 1158 XFree((void *)preedit); 1159 } 1160 #else /* !__linux__ */ 1161 #ifndef XAWT 1162 if (on_the_spot_styles & XIMStatusArea) { 1163 Widget parent; 1164 status = awt_motif_getXICStatusAreaList(w, tc); 1165 if (status == NULL) 1166 goto err; 1167 pX11IMData->statusWidget = awt_util_getXICStatusAreaWindow(w); 1168 pX11IMData->ic_active = XCreateIC(X11im, 1169 XNClientWindow, XtWindow(pX11IMData->statusWidget), 1170 XNFocusWindow, XtWindow(w), 1171 XNInputStyle, active_styles, 1172 XNPreeditAttributes, preedit, 1173 XNStatusAttributes, status, 1174 NULL); 1175 XFree((void *)status); 1176 } else { 1177 #endif /* XAWT */ 1178 pX11IMData->ic_active = XCreateIC(X11im, 1179 XNClientWindow, XtWindow(w), 1180 XNFocusWindow, XtWindow(w), 1181 XNInputStyle, active_styles, 1182 XNPreeditAttributes, preedit, 1183 NULL); 1184 #ifndef XAWT 1185 } 1186 #endif /* XAWT */ 1187 XFree((void *)preedit); 1188 #endif /* __linux__ */ 1189 pX11IMData->ic_passive = XCreateIC(X11im, 1190 XNClientWindow, XtWindow(w), 1191 XNFocusWindow, XtWindow(w), 1192 XNInputStyle, passive_styles, 1193 NULL); 1194 1195 } else { 1196 pX11IMData->ic_active = XCreateIC(X11im, 1197 XNClientWindow, XtWindow(w), 1198 XNFocusWindow, XtWindow(w), 1199 XNInputStyle, active_styles, 1200 NULL); 1201 pX11IMData->ic_passive = pX11IMData->ic_active; 1202 } 1203 1204 if (pX11IMData->ic_active == (XIC)0 1205 || pX11IMData->ic_passive == (XIC)0) { 1206 return False; 1207 } 1208 1209 /* 1210 * Use commit string call back if possible. 1211 * This will ensure the correct order of preedit text and commit text 1212 */ 1213 { 1214 XIMCallback cb; 1215 cb.client_data = (XPointer) pX11IMData->x11inputmethod; 1216 cb.callback = CommitStringCallback; 1217 XSetICValues (pX11IMData->ic_active, XNCommitStringCallback, &cb, NULL); 1218 if (pX11IMData->ic_active != pX11IMData->ic_passive) { 1219 XSetICValues (pX11IMData->ic_passive, XNCommitStringCallback, &cb, NULL); 1220 } 1221 } 1222 1223 /* Add the global reference object to X11InputMethod to the list. */ 1224 addToX11InputMethodGRefList(pX11IMData->x11inputmethod); 1225 1226 return True; 1227 1228 err: 1229 if (preedit) 1230 XFree((void *)preedit); 1231 THROW_OUT_OF_MEMORY_ERROR(); 1232 return False; 1233 } 1234 1235 static void 1236 PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data) 1237 { 1238 /*ARGSUSED*/ 1239 /* printf("Native: PreeditCaretCallback\n"); */ 1240 } 1241 1242 static void 1243 PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data) 1244 { 1245 /*ARGSUSED*/ 1246 /* printf("Native: StatusStartCallback\n"); */ 1247 } 1248 1249 /* 1250 * Translate the preedit draw callback items to Java values and invoke 1251 * X11InputMethod.dispatchComposedText(). 1252 * 1253 * client_data: X11InputMethod object 1254 */ 1255 static void 1256 PreeditDrawCallback(XIC ic, XPointer client_data, 1257 XIMPreeditDrawCallbackStruct *pre_draw) 1258 { 1259 JNIEnv *env = GetJNIEnv(); 1260 X11InputMethodData *pX11IMData = NULL; 1261 jmethodID x11imMethodID; 1262 1263 XIMText *text; 1264 jstring javastr = NULL; 1265 jintArray style = NULL; 1266 1267 /* printf("Native: PreeditDrawCallback() \n"); */ 1268 if (pre_draw == NULL) { 1269 return; 1270 } 1271 AWT_LOCK(); 1272 if (!isX11InputMethodGRefInList((jobject)client_data)) { 1273 if ((jobject)client_data == currentX11InputMethodInstance) { 1274 currentX11InputMethodInstance = NULL; 1275 } 1276 goto finally; 1277 } 1278 if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) { 1279 goto finally; 1280 } 1281 1282 if ((text = pre_draw->text) != NULL) { 1283 if (text->string.multi_byte != NULL) { 1284 if (pre_draw->text->encoding_is_wchar == False) { 1285 javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte); 1286 } else { 1287 char *mbstr = wcstombsdmp(text->string.wide_char, text->length); 1288 if (mbstr == NULL) { 1289 goto finally; 1290 } 1291 javastr = JNU_NewStringPlatform(env, (const char *)mbstr); 1292 free(mbstr); 1293 } 1294 } 1295 if (text->feedback != NULL) { 1296 int cnt; 1297 jint *tmpstyle; 1298 1299 style = (*env)->NewIntArray(env, text->length); 1300 if (JNU_IsNull(env, style)) { 1301 THROW_OUT_OF_MEMORY_ERROR(); 1302 goto finally; 1303 } 1304 1305 if (sizeof(XIMFeedback) == sizeof(jint)) { 1306 /* 1307 * Optimization to avoid copying the array 1308 */ 1309 (*env)->SetIntArrayRegion(env, style, 0, 1310 text->length, (jint *)text->feedback); 1311 } else { 1312 tmpstyle = (jint *)malloc(sizeof(jint)*(text->length)); 1313 if (tmpstyle == (jint *) NULL) { 1314 THROW_OUT_OF_MEMORY_ERROR(); 1315 goto finally; 1316 } 1317 for (cnt = 0; cnt < (int)text->length; cnt++) 1318 tmpstyle[cnt] = text->feedback[cnt]; 1319 (*env)->SetIntArrayRegion(env, style, 0, 1320 text->length, (jint *)tmpstyle); 1321 } 1322 } 1323 } 1324 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, 1325 "dispatchComposedText", 1326 "(Ljava/lang/String;[IIIIJ)V", 1327 javastr, 1328 style, 1329 (jint)pre_draw->chg_first, 1330 (jint)pre_draw->chg_length, 1331 (jint)pre_draw->caret, 1332 awt_util_nowMillisUTC()); 1333 finally: 1334 AWT_UNLOCK(); 1335 return; 1336 } 1337 1338 static void 1339 PreeditCaretCallback(XIC ic, XPointer client_data, 1340 XIMPreeditCaretCallbackStruct *pre_caret) 1341 { 1342 /*ARGSUSED*/ 1343 /* printf("Native: PreeditCaretCallback\n"); */ 1344 1345 } 1346 1347 #ifdef __linux__ 1348 static void 1349 StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data) 1350 { 1351 /*ARGSUSED*/ 1352 /*printf("StatusStartCallback:\n"); */ 1353 1354 } 1355 1356 static void 1357 StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data) 1358 { 1359 /*ARGSUSED*/ 1360 /*printf("StatusDoneCallback:\n"); */ 1361 1362 } 1363 1364 static void 1365 StatusDrawCallback(XIC ic, XPointer client_data, 1366 XIMStatusDrawCallbackStruct *status_draw) 1367 { 1368 /*ARGSUSED*/ 1369 /*printf("StatusDrawCallback:\n"); */ 1370 JNIEnv *env = GetJNIEnv(); 1371 X11InputMethodData *pX11IMData = NULL; 1372 StatusWindow *statusWindow; 1373 1374 AWT_LOCK(); 1375 1376 if (!isX11InputMethodGRefInList((jobject)client_data)) { 1377 if ((jobject)client_data == currentX11InputMethodInstance) { 1378 currentX11InputMethodInstance = NULL; 1379 } 1380 goto finally; 1381 } 1382 1383 if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data)) 1384 || NULL == (statusWindow = pX11IMData->statusWindow)){ 1385 goto finally; 1386 } 1387 currentX11InputMethodInstance = (jobject)client_data; 1388 1389 if (status_draw->type == XIMTextType){ 1390 XIMText *text = (status_draw->data).text; 1391 if (text != NULL){ 1392 if (text->string.multi_byte != NULL){ 1393 strcpy(statusWindow->status, text->string.multi_byte); 1394 } 1395 else{ 1396 char *mbstr = wcstombsdmp(text->string.wide_char, text->length); 1397 strcpy(statusWindow->status, mbstr); 1398 } 1399 statusWindow->on = True; 1400 onoffStatusWindow(pX11IMData, statusWindow->parent, True); 1401 paintStatusWindow(statusWindow); 1402 } 1403 else { 1404 statusWindow->on = False; 1405 /*just turnoff the status window 1406 paintStatusWindow(statusWindow); 1407 */ 1408 onoffStatusWindow(pX11IMData, 0, False); 1409 } 1410 } 1411 1412 finally: 1413 AWT_UNLOCK(); 1414 } 1415 #endif /*__linux__*/ 1416 1417 static void CommitStringCallback(XIC ic, XPointer client_data, XPointer call_data) { 1418 JNIEnv *env = GetJNIEnv(); 1419 XIMText * text = (XIMText *)call_data; 1420 X11InputMethodData *pX11IMData = NULL; 1421 jstring javastr; 1422 1423 AWT_LOCK(); 1424 1425 if (!isX11InputMethodGRefInList((jobject)client_data)) { 1426 if ((jobject)client_data == currentX11InputMethodInstance) { 1427 currentX11InputMethodInstance = NULL; 1428 } 1429 goto finally; 1430 } 1431 1432 if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) { 1433 goto finally; 1434 } 1435 currentX11InputMethodInstance = (jobject)client_data; 1436 1437 if (text->encoding_is_wchar == False) { 1438 javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte); 1439 } else { 1440 char *mbstr = wcstombsdmp(text->string.wide_char, text->length); 1441 if (mbstr == NULL) { 1442 goto finally; 1443 } 1444 javastr = JNU_NewStringPlatform(env, (const char *)mbstr); 1445 free(mbstr); 1446 } 1447 1448 if (javastr != NULL) { 1449 JNU_CallMethodByName(env, NULL, 1450 pX11IMData->x11inputmethod, 1451 "dispatchCommittedText", 1452 "(Ljava/lang/String;J)V", 1453 javastr, 1454 awt_util_nowMillisUTC()); 1455 } 1456 finally: 1457 AWT_UNLOCK(); 1458 } 1459 1460 static void OpenXIMCallback(Display *display, XPointer client_data, XPointer call_data) { 1461 XIMCallback ximCallback; 1462 1463 X11im = XOpenIM(display, NULL, NULL, NULL); 1464 if (X11im == NULL) { 1465 return; 1466 } 1467 1468 ximCallback.callback = (XIMProc)DestroyXIMCallback; 1469 ximCallback.client_data = NULL; 1470 XSetIMValues(X11im, XNDestroyCallback, &ximCallback, NULL); 1471 } 1472 1473 static void DestroyXIMCallback(XIM im, XPointer client_data, XPointer call_data) { 1474 /* mark that XIM server was destroyed */ 1475 X11im = NULL; 1476 } 1477 1478 /* 1479 * Class: java_sun_awt_motif_X11InputMethod 1480 * Method: initIDs 1481 * Signature: ()V 1482 */ 1483 1484 /* This function gets called from the static initializer for 1485 X11InputMethod.java 1486 to initialize the fieldIDs for fields that may be accessed from C */ 1487 JNIEXPORT void JNICALL 1488 Java_sun_awt_X11InputMethod_initIDs(JNIEnv *env, jclass cls) 1489 { 1490 x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"); 1491 } 1492 1493 1494 JNIEXPORT jboolean JNICALL 1495 #ifdef XAWT 1496 Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env, 1497 jobject this, 1498 jlong display) 1499 #else 1500 Java_sun_awt_motif_MInputMethod_openXIMNative(JNIEnv *env, 1501 jobject this) 1502 #endif 1503 { 1504 Bool registered; 1505 1506 AWT_LOCK(); 1507 1508 #ifdef XAWT 1509 dpy = (Display *)display; 1510 #else 1511 dpy = awt_display; 1512 #endif 1513 1514 /* Use IMInstantiate call back only on Linux, as there is a bug in Solaris 1515 (4768335) 1516 */ 1517 #ifdef __linux__ 1518 registered = XRegisterIMInstantiateCallback(dpy, NULL, NULL, 1519 NULL, (XIMProc)OpenXIMCallback, NULL); 1520 if (!registered) { 1521 /* directly call openXIM callback */ 1522 #endif 1523 OpenXIMCallback(dpy, NULL, NULL); 1524 #ifdef __linux__ 1525 } 1526 #endif 1527 1528 AWT_UNLOCK(); 1529 1530 return JNI_TRUE; 1531 } 1532 1533 JNIEXPORT jboolean JNICALL 1534 #ifdef XAWT 1535 Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env, 1536 jobject this, 1537 jlong window) 1538 { 1539 #else /* !XAWT */ 1540 Java_sun_awt_motif_MInputMethod_createXICNative(JNIEnv *env, 1541 jobject this, 1542 jobject comp, 1543 jobject tc) 1544 { 1545 struct ComponentData *cdata; 1546 #endif /* XAWT */ 1547 X11InputMethodData *pX11IMData; 1548 jobject globalRef; 1549 XIC ic; 1550 1551 AWT_LOCK(); 1552 1553 #ifdef XAWT 1554 if (window == NULL) { 1555 #else /* !XAWT */ 1556 if (JNU_IsNull(env, comp)) { 1557 #endif /* XAWT */ 1558 JNU_ThrowNullPointerException(env, "NullPointerException"); 1559 AWT_UNLOCK(); 1560 return JNI_FALSE; 1561 } 1562 1563 pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData)); 1564 if (pX11IMData == NULL) { 1565 THROW_OUT_OF_MEMORY_ERROR(); 1566 AWT_UNLOCK(); 1567 return JNI_FALSE; 1568 } 1569 1570 #ifndef XAWT 1571 if (mcompClass == NULL) { 1572 mcompClass = findClass(MCOMPONENTPEER_CLASS_NAME); 1573 mcompPDataID = (*env)->GetFieldID(env, mcompClass, "pData", "J"); 1574 } 1575 cdata = (struct ComponentData *) JNU_GetLongFieldAsPtr(env,comp,mcompPDataID); 1576 1577 if (cdata == 0) { 1578 free((void *)pX11IMData); 1579 JNU_ThrowNullPointerException(env, "createXIC"); 1580 AWT_UNLOCK(); 1581 return JNI_FALSE; 1582 } 1583 1584 pX11IMData->peer = (*env)->NewGlobalRef(env, comp); 1585 #endif /* XAWT */ 1586 globalRef = (*env)->NewGlobalRef(env, this); 1587 pX11IMData->x11inputmethod = globalRef; 1588 #ifdef __linux__ 1589 pX11IMData->statusWindow = NULL; 1590 #else /* __linux__ */ 1591 #ifndef XAWT 1592 pX11IMData->statusWidget = (Widget) NULL; 1593 #endif /* XAWT */ 1594 #endif /* __linux__ */ 1595 1596 pX11IMData->lookup_buf = 0; 1597 pX11IMData->lookup_buf_len = 0; 1598 1599 #ifdef XAWT 1600 if (createXIC(env, pX11IMData, (Window)window) 1601 #else /* !XAWT */ 1602 if (createXIC(cdata->widget, pX11IMData, tc, comp) 1603 #endif /* XAWT */ 1604 == False) { 1605 destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData); 1606 pX11IMData = (X11InputMethodData *) NULL; 1607 } 1608 1609 setX11InputMethodData(env, this, pX11IMData); 1610 1611 AWT_UNLOCK(); 1612 return (pX11IMData != NULL); 1613 } 1614 1615 #ifndef XAWT 1616 JNIEXPORT void JNICALL 1617 Java_sun_awt_motif_MInputMethod_reconfigureXICNative(JNIEnv *env, 1618 jobject this, 1619 jobject comp, 1620 jobject tc) 1621 { 1622 X11InputMethodData *pX11IMData; 1623 1624 AWT_LOCK(); 1625 1626 pX11IMData = getX11InputMethodData(env, this); 1627 if (pX11IMData == NULL) { 1628 AWT_UNLOCK(); 1629 return; 1630 } 1631 1632 if (pX11IMData->current_ic == (XIC)0) { 1633 destroyX11InputMethodData(env, pX11IMData); 1634 pX11IMData = (X11InputMethodData *)NULL; 1635 } else { 1636 Bool active; 1637 struct ComponentData *cdata; 1638 1639 active = pX11IMData->current_ic == pX11IMData->ic_active; 1640 if (mcompClass == NULL) { 1641 mcompClass = findClass(MCOMPONENTPEER_CLASS_NAME); 1642 mcompPDataID = (*env)->GetFieldID(env, mcompClass, "pData", "J"); 1643 } 1644 cdata = (struct ComponentData *) JNU_GetLongFieldAsPtr(env,comp,mcompPDataID); 1645 if (cdata == 0) { 1646 JNU_ThrowNullPointerException(env, "reconfigureXICNative"); 1647 destroyX11InputMethodData(env, pX11IMData); 1648 pX11IMData = (X11InputMethodData *)NULL; 1649 } 1650 XDestroyIC(pX11IMData->ic_active); 1651 if (pX11IMData->ic_active != pX11IMData->ic_passive) 1652 XDestroyIC(pX11IMData->ic_passive); 1653 pX11IMData->current_ic = (XIC)0; 1654 pX11IMData->ic_active = (XIC)0; 1655 pX11IMData->ic_passive = (XIC)0; 1656 if (createXIC(cdata->widget, pX11IMData, tc, comp)) { 1657 pX11IMData->current_ic = active ? 1658 pX11IMData->ic_active : pX11IMData->ic_passive; 1659 /* 1660 * On Solaris2.6, setXICWindowFocus() has to be invoked 1661 * before setting focus. 1662 */ 1663 setXICWindowFocus(pX11IMData->current_ic, XtWindow(cdata->widget)); 1664 setXICFocus(pX11IMData->current_ic, True); 1665 } else { 1666 destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData); 1667 pX11IMData = (X11InputMethodData *)NULL; 1668 } 1669 } 1670 1671 setX11InputMethodData(env, this, pX11IMData); 1672 1673 AWT_UNLOCK(); 1674 } 1675 1676 JNIEXPORT void JNICALL 1677 Java_sun_awt_motif_MInputMethod_setXICFocusNative(JNIEnv *env, 1678 jobject this, 1679 jobject comp, 1680 jboolean req, 1681 jboolean active) 1682 { 1683 struct ComponentData *cdata; 1684 Widget w; 1685 #else /* !XAWT */ 1686 JNIEXPORT void JNICALL 1687 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env, 1688 jobject this, 1689 jlong w, 1690 jboolean req, 1691 jboolean active) 1692 { 1693 #endif /* XAWT */ 1694 X11InputMethodData *pX11IMData; 1695 AWT_LOCK(); 1696 pX11IMData = getX11InputMethodData(env, this); 1697 if (pX11IMData == NULL) { 1698 AWT_UNLOCK(); 1699 return; 1700 } 1701 1702 if (req) { 1703 #ifdef XAWT 1704 if (w == NULL) { 1705 AWT_UNLOCK(); 1706 return; 1707 } 1708 #else /* !XAWT */ 1709 struct ComponentData *cdata; 1710 1711 if (JNU_IsNull(env, comp)) { 1712 AWT_UNLOCK(); 1713 return; 1714 } 1715 if (mcompClass == NULL) { 1716 mcompClass = findClass(MCOMPONENTPEER_CLASS_NAME); 1717 mcompPDataID = (*env)->GetFieldID(env, mcompClass, "pData", "J"); 1718 } 1719 cdata = (struct ComponentData *)JNU_GetLongFieldAsPtr(env, comp, 1720 mcompPDataID); 1721 if (cdata == 0) { 1722 JNU_ThrowNullPointerException(env, "setXICFocus pData"); 1723 AWT_UNLOCK(); 1724 return; 1725 } 1726 #endif /* XAWT */ 1727 1728 pX11IMData->current_ic = active ? 1729 pX11IMData->ic_active : pX11IMData->ic_passive; 1730 /* 1731 * On Solaris2.6, setXICWindowFocus() has to be invoked 1732 * before setting focus. 1733 */ 1734 #ifndef XAWT 1735 w = cdata->widget; 1736 #endif /* XAWT */ 1737 setXICWindowFocus(pX11IMData->current_ic, XtWindow(w)); 1738 setXICFocus(pX11IMData->current_ic, req); 1739 currentX11InputMethodInstance = pX11IMData->x11inputmethod; 1740 currentFocusWindow = XtWindow(w); 1741 #ifdef __linux__ 1742 if (active && pX11IMData->statusWindow && pX11IMData->statusWindow->on) 1743 onoffStatusWindow(pX11IMData, w, True); 1744 #endif 1745 } else { 1746 currentX11InputMethodInstance = NULL; 1747 currentFocusWindow = 0; 1748 #ifdef __linux__ 1749 onoffStatusWindow(pX11IMData, 0, False); 1750 if (pX11IMData->current_ic != NULL) 1751 #endif 1752 setXICFocus(pX11IMData->current_ic, req); 1753 1754 pX11IMData->current_ic = (XIC)0; 1755 } 1756 1757 XFlush(dpy); 1758 AWT_UNLOCK(); 1759 } 1760 1761 JNIEXPORT void JNICALL 1762 Java_sun_awt_X11InputMethod_turnoffStatusWindow(JNIEnv *env, 1763 jobject this) 1764 { 1765 #ifdef __linux__ 1766 X11InputMethodData *pX11IMData; 1767 StatusWindow *statusWindow; 1768 1769 AWT_LOCK(); 1770 1771 if (NULL == currentX11InputMethodInstance 1772 || !isX11InputMethodGRefInList(currentX11InputMethodInstance) 1773 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance)) 1774 || NULL == (statusWindow = pX11IMData->statusWindow) 1775 || !statusWindow->on ){ 1776 AWT_UNLOCK(); 1777 return; 1778 } 1779 onoffStatusWindow(pX11IMData, 0, False); 1780 1781 AWT_UNLOCK(); 1782 #endif 1783 } 1784 1785 JNIEXPORT void JNICALL 1786 Java_sun_awt_X11InputMethod_disposeXIC(JNIEnv *env, 1787 jobject this) 1788 { 1789 X11InputMethodData *pX11IMData = NULL; 1790 1791 AWT_LOCK(); 1792 pX11IMData = getX11InputMethodData(env, this); 1793 if (pX11IMData == NULL) { 1794 AWT_UNLOCK(); 1795 return; 1796 } 1797 1798 setX11InputMethodData(env, this, NULL); 1799 1800 if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) { 1801 currentX11InputMethodInstance = NULL; 1802 currentFocusWindow = 0; 1803 } 1804 destroyX11InputMethodData(env, pX11IMData); 1805 AWT_UNLOCK(); 1806 } 1807 1808 JNIEXPORT jstring JNICALL 1809 Java_sun_awt_X11InputMethod_resetXIC(JNIEnv *env, 1810 jobject this) 1811 { 1812 X11InputMethodData *pX11IMData; 1813 char *xText = NULL; 1814 jstring jText = (jstring)0; 1815 1816 AWT_LOCK(); 1817 pX11IMData = getX11InputMethodData(env, this); 1818 if (pX11IMData == NULL) { 1819 AWT_UNLOCK(); 1820 return jText; 1821 } 1822 1823 if (pX11IMData->current_ic) 1824 xText = XmbResetIC(pX11IMData->current_ic); 1825 else { 1826 /* 1827 * If there is no reference to the current XIC, try to reset both XICs. 1828 */ 1829 xText = XmbResetIC(pX11IMData->ic_active); 1830 /*it may also means that the real client component does 1831 not have focus -- has been deactivated... its xic should 1832 not have the focus, bug#4284651 showes reset XIC for htt 1833 may bring the focus back, so de-focus it again. 1834 */ 1835 setXICFocus(pX11IMData->ic_active, FALSE); 1836 if (pX11IMData->ic_active != pX11IMData->ic_passive) { 1837 char *tmpText = XmbResetIC(pX11IMData->ic_passive); 1838 setXICFocus(pX11IMData->ic_passive, FALSE); 1839 if (xText == (char *)NULL && tmpText) 1840 xText = tmpText; 1841 } 1842 1843 } 1844 if (xText != NULL) { 1845 jText = JNU_NewStringPlatform(env, (const char *)xText); 1846 XFree((void *)xText); 1847 } 1848 1849 AWT_UNLOCK(); 1850 return jText; 1851 } 1852 1853 #ifndef XAWT 1854 JNIEXPORT void JNICALL 1855 Java_sun_awt_motif_MInputMethod_configureStatusAreaNative(JNIEnv *env, 1856 jobject this, 1857 jobject tc) 1858 { 1859 X11InputMethodData *pX11IMData; 1860 XVaNestedList status; 1861 1862 #ifdef __linux__ 1863 /*do nothing for linux? */ 1864 #else 1865 AWT_LOCK(); 1866 pX11IMData = getX11InputMethodData(env, this); 1867 1868 if ((pX11IMData == NULL) || (pX11IMData->ic_active == (XIC)0)) { 1869 AWT_UNLOCK(); 1870 return; 1871 } 1872 1873 if (pX11IMData->statusWidget) { 1874 status = awt_motif_getXICStatusAreaList(pX11IMData->statusWidget, tc); 1875 if (status != (XVaNestedList)NULL) { 1876 XSetICValues(pX11IMData->ic_active, 1877 XNStatusAttributes, status, 1878 NULL); 1879 XFree((void *)status); 1880 } 1881 } 1882 AWT_UNLOCK(); 1883 #endif 1884 } 1885 #endif /* XAWT */ 1886 1887 /* 1888 * Class: sun_awt_X11InputMethod 1889 * Method: setCompositionEnabledNative 1890 * Signature: (ZJ)V 1891 * 1892 * This method tries to set the XNPreeditState attribute associated with the current 1893 * XIC to the passed in 'enable' state. 1894 * 1895 * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the 1896 * 'enable' state; Otherwise, if XSetICValues fails to set this attribute, 1897 * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this 1898 * method fails due to other reasons. 1899 * 1900 */ 1901 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_setCompositionEnabledNative 1902 (JNIEnv *env, jobject this, jboolean enable) 1903 { 1904 X11InputMethodData *pX11IMData; 1905 char * ret = NULL; 1906 1907 AWT_LOCK(); 1908 pX11IMData = getX11InputMethodData(env, this); 1909 1910 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { 1911 AWT_UNLOCK(); 1912 return JNI_FALSE; 1913 } 1914 1915 ret = XSetICValues(pX11IMData->current_ic, XNPreeditState, 1916 (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL); 1917 AWT_UNLOCK(); 1918 1919 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) { 1920 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); 1921 } 1922 1923 return (jboolean)(ret == 0); 1924 } 1925 1926 /* 1927 * Class: sun_awt_X11InputMethod 1928 * Method: isCompositionEnabledNative 1929 * Signature: (J)Z 1930 * 1931 * This method tries to get the XNPreeditState attribute associated with the current XIC. 1932 * 1933 * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if 1934 * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException 1935 * will be thrown. JNI_FALSE is returned if this method fails due to other reasons. 1936 * 1937 */ 1938 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_isCompositionEnabledNative 1939 (JNIEnv *env, jobject this) 1940 { 1941 X11InputMethodData *pX11IMData = NULL; 1942 char * ret = NULL; 1943 XIMPreeditState state; 1944 1945 AWT_LOCK(); 1946 pX11IMData = getX11InputMethodData(env, this); 1947 1948 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { 1949 AWT_UNLOCK(); 1950 return JNI_FALSE; 1951 } 1952 1953 ret = XGetICValues(pX11IMData->current_ic, XNPreeditState, &state, NULL); 1954 AWT_UNLOCK(); 1955 1956 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) { 1957 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); 1958 return JNI_FALSE; 1959 } 1960 1961 return (jboolean)(state == XIMPreeditEnable); 1962 } 1963 1964 #ifdef XAWT 1965 JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow 1966 (JNIEnv *env, jobject this, jlong window) 1967 { 1968 #ifdef __linux__ 1969 AWT_LOCK(); 1970 adjustStatusWindow(window); 1971 AWT_UNLOCK(); 1972 #endif 1973 } 1974 #endif