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