1 /*
2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #ifdef HEADLESS
27 #error This file should not be included in headless library
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <X11/Xlib.h>
33 #include <X11/keysym.h>
34 #include <sys/time.h>
35
36 #include "awt.h"
37 #include "awt_p.h"
38
39 #include <sun_awt_X11InputMethod.h>
40 #include <sun_awt_X11_XInputMethod.h>
41
42 #define THROW_OUT_OF_MEMORY_ERROR() \
43 JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL)
44
45 struct X11InputMethodIDs {
46 jfieldID pData;
47 } x11InputMethodIDs;
48
49 static void PreeditStartCallback(XIC, XPointer, XPointer);
50 static void PreeditDoneCallback(XIC, XPointer, XPointer);
51 static void PreeditDrawCallback(XIC, XPointer,
52 XIMPreeditDrawCallbackStruct *);
53 static void PreeditCaretCallback(XIC, XPointer,
54 XIMPreeditCaretCallbackStruct *);
55 #if defined(__linux__) || defined(MACOSX)
56 static void StatusStartCallback(XIC, XPointer, XPointer);
57 static void StatusDoneCallback(XIC, XPointer, XPointer);
58 static void StatusDrawCallback(XIC, XPointer,
59 XIMStatusDrawCallbackStruct *);
60 #endif
61
519 mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf,
520 pX11IMData->lookup_buf_len - 1, &keysym, &status);
521 }
522 pX11IMData->lookup_buf[mblen] = 0;
523
524 /* Get keysym without taking modifiers into account first to map
525 * to AWT keyCode table.
526 */
527 switch (status) {
528 case XLookupBoth:
529 if (!composing) {
530 if (event->keycode != 0) {
531 *keysymp = keysym;
532 result = False;
533 break;
534 }
535 }
536 composing = False;
537 /*FALLTHRU*/
538 case XLookupChars:
539 /*
540 printf("lookupString: status=XLookupChars, type=%d, state=%x, keycode=%x, keysym=%x\n",
541 event->type, event->state, event->keycode, keysym);
542 */
543 javastr = JNU_NewStringPlatform(env, (const char *)pX11IMData->lookup_buf);
544 if (javastr != NULL) {
545 JNU_CallMethodByName(env, NULL,
546 currentX11InputMethodInstance,
547 "dispatchCommittedText",
548 "(Ljava/lang/String;J)V",
549 javastr,
550 event->time);
551 }
552 break;
553
554 case XLookupKeySym:
555 /*
556 printf("lookupString: status=XLookupKeySym, type=%d, state=%x, keycode=%x, keysym=%x\n",
557 event->type, event->state, event->keycode, keysym);
558 */
559 if (keysym == XK_Multi_key)
560 composing = True;
561 if (! composing) {
562 *keysymp = keysym;
563 result = False;
564 }
565 break;
566
567 case XLookupNone:
568 /*
569 printf("lookupString: status=XLookupNone, type=%d, state=%x, keycode=%x, keysym=%x\n",
570 event->type, event->state, event->keycode, keysym);
571 */
572 break;
573 }
574
575 return result;
576 }
577
578 #if defined(__linux__) || defined(MACOSX)
579 static StatusWindow *createStatusWindow(
580 Window parent) {
581 StatusWindow *statusWindow;
582 XSetWindowAttributes attrib;
583 unsigned long attribmask;
584 Window containerWindow;
585 Window status;
586 Window child;
587 XWindowAttributes xwa;
588 XWindowAttributes xxwa;
589 /* Variable for XCreateFontSet()*/
590 char **mclr;
591 int mccr = 0;
592 char *dsr;
593 unsigned long bg, fg, light, dim;
594 int x, y, off_x, off_y, xx, yy;
595 unsigned int w, h, bw, depth;
596 XGCValues values;
597 unsigned long valuemask = 0; /*ignore XGCvalue and use defaults*/
598 int screen = 0;
599 int i;
600 AwtGraphicsConfigDataPtr adata;
601 extern int awt_numScreens;
602 /*hardcode the size right now, should get the size base on font*/
603 int width=80, height=22;
604 Window rootWindow;
605 Window *ignoreWindowPtr;
606 unsigned int ignoreUnit;
607
608 XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth);
609
610 attrib.override_redirect = True;
611 attribmask = CWOverrideRedirect;
612 for (i = 0; i < awt_numScreens; i++) {
613 if (RootWindow(dpy, i) == rootWindow) {
614 screen = i;
615 break;
616 }
617 }
618 adata = getDefaultConfig(screen);
619 bg = adata->AwtColorMatch(255, 255, 255, adata);
620 fg = adata->AwtColorMatch(0, 0, 0, adata);
621 light = adata->AwtColorMatch(195, 195, 195, adata);
622 dim = adata->AwtColorMatch(128, 128, 128, adata);
623
635 &ignoreWindowPtr,
636 &ignoreUnit);
637 XGetWindowAttributes(dpy, containerWindow, &xxwa);
638
639 off_x = (xxwa.width - xwa.width) / 2;
640 off_y = xxwa.height - xwa.height - off_x; /*it's magic:-) */
641
642 /*get the size of root window*/
643 XGetWindowAttributes(dpy, rootWindow, &xxwa);
644
645 XTranslateCoordinates(dpy,
646 parent, xwa.root,
647 xwa.x, xwa.y,
648 &x, &y,
649 &child);
650 xx = x - off_x;
651 yy = y + xwa.height - off_y;
652 if (xx < 0 ){
653 xx = 0;
654 }
655 if (xx + width > xxwa.width){
656 xx = xxwa.width - width;
657 }
658 if (yy + height > xxwa.height){
659 yy = xxwa.height - height;
660 }
661
662 status = XCreateWindow(dpy,
663 xwa.root,
664 xx, yy,
665 width, height,
666 0,
667 xwa.depth,
668 InputOutput,
669 adata->awt_visInfo.visual,
670 attribmask, &attrib);
671 XSelectInput(dpy, status,
672 ExposureMask | StructureNotifyMask | EnterWindowMask |
673 LeaveWindowMask | VisibilityChangeMask);
674 statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow));
675 if (statusWindow == NULL){
676 THROW_OUT_OF_MEMORY_ERROR();
677 return NULL;
678 }
707 statusWindow->bgGC = XCreateGC(dpy, status, valuemask, &values);
708 XSetForeground(dpy, statusWindow->bgGC, bg);
709 return statusWindow;
710 }
711
712 /* This method is to turn off or turn on the status window. */
713 static void onoffStatusWindow(X11InputMethodData* pX11IMData,
714 Window parent,
715 Bool ON){
716 XWindowAttributes xwa;
717 Window child;
718 int x, y;
719 StatusWindow *statusWindow = NULL;
720
721 if (NULL == currentX11InputMethodInstance ||
722 NULL == pX11IMData ||
723 NULL == (statusWindow = pX11IMData->statusWindow)){
724 return;
725 }
726
727 if (ON == False){
728 XUnmapWindow(dpy, statusWindow->w);
729 statusWindow->on = False;
730 return;
731 }
732 parent = JNU_CallMethodByName(GetJNIEnv(), NULL, pX11IMData->x11inputmethod,
733 "getCurrentParentWindow",
734 "()J").j;
735 if (statusWindow->parent != parent){
736 statusWindow->parent = parent;
737 }
738 XGetWindowAttributes(dpy, parent, &xwa);
739 XTranslateCoordinates(dpy,
740 parent, xwa.root,
741 xwa.x, xwa.y,
742 &x, &y,
743 &child);
744 if (statusWindow->x != x
745 || statusWindow->y != y
746 || statusWindow->height != xwa.height){
747 statusWindow->x = x;
748 statusWindow->y = y;
749 statusWindow->height = xwa.height;
750 x = statusWindow->x - statusWindow->off_x;
751 y = statusWindow->y + statusWindow->height - statusWindow->off_y;
752 if (x < 0 ){
753 x = 0;
754 }
755 if (x + statusWindow->statusW > statusWindow->rootW){
756 x = statusWindow->rootW - statusWindow->statusW;
757 }
758 if (y + statusWindow->statusH > statusWindow->rootH){
759 y = statusWindow->rootH - statusWindow->statusH;
760 }
761 XMoveWindow(dpy, statusWindow->w, x, y);
762 }
763 statusWindow->on = True;
764 XMapWindow(dpy, statusWindow->w);
765 }
766
767 void paintStatusWindow(StatusWindow *statusWindow){
768 Window win = statusWindow->w;
769 GC lightgc = statusWindow->lightGC;
770 GC dimgc = statusWindow->dimGC;
771 GC bggc = statusWindow->bgGC;
772 GC fggc = statusWindow->fgGC;
773
774 int width = statusWindow->statusW;
775 int height = statusWindow->statusH;
776 int bwidth = statusWindow->bWidth;
777 XFillRectangle(dpy, win, bggc, 0, 0, width, height);
778 /* draw border */
779 XDrawLine(dpy, win, fggc, 0, 0, width, 0);
780 XDrawLine(dpy, win, fggc, 0, height-1, width-1, height-1);
781 XDrawLine(dpy, win, fggc, 0, 0, 0, height-1);
782 XDrawLine(dpy, win, fggc, width-1, 0, width-1, height-1);
783
784 XDrawLine(dpy, win, lightgc, 1, 1, width-bwidth, 1);
785 XDrawLine(dpy, win, lightgc, 1, 1, 1, height-2);
786 XDrawLine(dpy, win, lightgc, 1, height-2, width-bwidth, height-2);
787 XDrawLine(dpy, win, lightgc, width-bwidth-1, 1, width-bwidth-1, height-2);
788
789 XDrawLine(dpy, win, dimgc, 2, 2, 2, height-3);
790 XDrawLine(dpy, win, dimgc, 2, height-3, width-bwidth-1, height-3);
791 XDrawLine(dpy, win, dimgc, 2, 2, width-bwidth-2, 2);
792 XDrawLine(dpy, win, dimgc, width-bwidth, 2, width-bwidth, height-3);
793 if (statusWindow->fontset){
794 XmbDrawString(dpy, win, statusWindow->fontset, fggc,
795 bwidth + 2, height - bwidth - 4,
796 statusWindow->status,
797 strlen(statusWindow->status));
798 }
799 else{
800 /*too bad we failed to create a fontset for this locale*/
801 XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4,
802 "[InputMethod ON]", strlen("[InputMethod ON]"));
803 }
804 }
805
806 void statusWindowEventHandler(XEvent event){
807 JNIEnv *env = GetJNIEnv();
808 X11InputMethodData *pX11IMData = NULL;
809 StatusWindow *statusWindow;
810
811 if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) {
812 currentX11InputMethodInstance = NULL;
813 return;
814 }
815
816 if (NULL == currentX11InputMethodInstance
817 || NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance))
818 || NULL == (statusWindow = pX11IMData->statusWindow)
819 || statusWindow->w != event.xany.window){
820 return;
821 }
822
823 switch (event.type){
824 case Expose:
825 paintStatusWindow(statusWindow);
826 break;
827 case MapNotify:
828 case ConfigureNotify:
829 {
830 /*need to reset the stackMode...*/
831 XWindowChanges xwc;
832 int value_make = CWStackMode;
833 xwc.stack_mode = TopIf;
834 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
835 }
836 break;
837 /*
838 case UnmapNotify:
839 case VisibilityNotify:
840 break;
841 */
842 default:
843 break;
844 }
845 }
846
847 static void adjustStatusWindow(Window shell){
848 JNIEnv *env = GetJNIEnv();
849 X11InputMethodData *pX11IMData = NULL;
850 StatusWindow *statusWindow;
851
852 if (NULL == currentX11InputMethodInstance
853 || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
854 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
855 || NULL == (statusWindow = pX11IMData->statusWindow)
856 || !statusWindow->on) {
857 return;
858 }
859 {
860 XWindowAttributes xwa;
861 int x, y;
862 Window child;
863 XGetWindowAttributes(dpy, shell, &xwa);
864 XTranslateCoordinates(dpy,
865 shell, xwa.root,
866 xwa.x, xwa.y,
867 &x, &y,
868 &child);
869 if (statusWindow->x != x
870 || statusWindow->y != y
871 || statusWindow->height != xwa.height){
872 statusWindow->x = x;
873 statusWindow->y = y;
874 statusWindow->height = xwa.height;
875
876 x = statusWindow->x - statusWindow->off_x;
877 y = statusWindow->y + statusWindow->height - statusWindow->off_y;
878 if (x < 0 ){
879 x = 0;
880 }
881 if (x + statusWindow->statusW > statusWindow->rootW){
882 x = statusWindow->rootW - statusWindow->statusW;
883 }
884 if (y + statusWindow->statusH > statusWindow->rootH){
885 y = statusWindow->rootH - statusWindow->statusH;
886 }
887 XMoveWindow(dpy, statusWindow->w, x, y);
888 }
889 }
890 }
891 #endif /* __linux__ || MACOSX */
892 /*
893 * Creates two XICs, one for active clients and the other for passive
894 * clients. All information on those XICs are stored in the
895 * X11InputMethodData given by the pX11IMData parameter.
896 *
897 * For active clients: Try to use preedit callback to support
898 * on-the-spot. If tc is not null, the XIC to be created will
899 * share the Status Area with Motif widgets (TextComponents). If the
900 * preferable styles can't be used, fallback to root-window styles. If
901 * root-window styles failed, fallback to None styles.
902 *
903 * For passive clients: Try to use root-window styles. If failed,
904 * fallback to None styles.
905 */
906 static Bool
907 createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w)
908 {
909 XVaNestedList preedit = NULL;
910 XVaNestedList status = NULL;
911 XIMStyle on_the_spot_styles = XIMPreeditCallbacks,
914 no_styles = 0;
915 XIMCallback *callbacks;
916 unsigned short i;
917 XIMStyles *im_styles;
918 char *ret = NULL;
919
920 if (X11im == NULL) {
921 return False;
922 }
923 if (!w) {
924 return False;
925 }
926
927 ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL);
928
929 if (ret != NULL) {
930 jio_fprintf(stderr,"XGetIMValues: %s\n",ret);
931 return FALSE ;
932 }
933
934 #if defined(__linux__) || defined(MACOSX)
935 on_the_spot_styles |= XIMStatusNothing;
936
937 /*kinput does not support XIMPreeditCallbacks and XIMStatusArea
938 at the same time, so use StatusCallback to draw the status
939 ourself
940 */
941 for (i = 0; i < im_styles->count_styles; i++) {
942 if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) {
943 on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks);
944 break;
945 }
946 }
947 #else /*! __linux__ && !MACOSX */
948 on_the_spot_styles |= XIMStatusNothing;
949 #endif /* __linux__ || MACOSX */
950
951 for (i = 0; i < im_styles->count_styles; i++) {
952 active_styles |= im_styles->supported_styles[i] & on_the_spot_styles;
953 passive_styles |= im_styles->supported_styles[i] & ROOT_WINDOW_STYLES;
954 no_styles |= im_styles->supported_styles[i] & NO_STYLES;
955 }
956
957 XFree(im_styles);
958
959 if (active_styles != on_the_spot_styles) {
960 if (passive_styles == ROOT_WINDOW_STYLES)
961 active_styles = passive_styles;
962 else {
963 if (no_styles == NO_STYLES)
964 active_styles = passive_styles = NO_STYLES;
965 else
966 active_styles = passive_styles = 0;
967 }
968 } else {
1006 status = (XVaNestedList)XVaCreateNestedList(0,
1007 XNStatusStartCallback, &callbacks[StatusStartIndex],
1008 XNStatusDoneCallback, &callbacks[StatusDoneIndex],
1009 XNStatusDrawCallback, &callbacks[StatusDrawIndex],
1010 NULL);
1011
1012 if (status == NULL)
1013 goto err;
1014 pX11IMData->statusWindow = createStatusWindow(w);
1015 pX11IMData->ic_active = XCreateIC(X11im,
1016 XNClientWindow, w,
1017 XNFocusWindow, w,
1018 XNInputStyle, active_styles,
1019 XNPreeditAttributes, preedit,
1020 XNStatusAttributes, status,
1021 NULL);
1022 XFree((void *)status);
1023 XFree((void *)preedit);
1024 }
1025 #else /* !__linux__ && !MACOSX */
1026 pX11IMData->ic_active = XCreateIC(X11im,
1027 XNClientWindow, w,
1028 XNFocusWindow, w,
1029 XNInputStyle, active_styles,
1030 XNPreeditAttributes, preedit,
1031 NULL);
1032 XFree((void *)preedit);
1033 #endif /* __linux__ || MACOSX */
1034 } else {
1035 pX11IMData->ic_active = XCreateIC(X11im,
1036 XNClientWindow, w,
1037 XNFocusWindow, w,
1038 XNInputStyle, active_styles,
1039 NULL);
1040 pX11IMData->ic_passive = pX11IMData->ic_active;
1041 }
1042
1043 if (pX11IMData->ic_active == (XIC)0
1044 || pX11IMData->ic_passive == (XIC)0) {
1045 return False;
1046 }
1047
1048 /*
1049 * Use commit string call back if possible.
1050 * This will ensure the correct order of preedit text and commit text
1051 */
1058 XSetICValues (pX11IMData->ic_passive, XNCommitStringCallback, &cb, NULL);
1059 }
1060 }
1061
1062 /* Add the global reference object to X11InputMethod to the list. */
1063 addToX11InputMethodGRefList(pX11IMData->x11inputmethod);
1064
1065 return True;
1066
1067 err:
1068 if (preedit)
1069 XFree((void *)preedit);
1070 THROW_OUT_OF_MEMORY_ERROR();
1071 return False;
1072 }
1073
1074 static void
1075 PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1076 {
1077 /*ARGSUSED*/
1078 /* printf("Native: PreeditCaretCallback\n"); */
1079 }
1080
1081 static void
1082 PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1083 {
1084 /*ARGSUSED*/
1085 /* printf("Native: StatusStartCallback\n"); */
1086 }
1087
1088 /*
1089 * Translate the preedit draw callback items to Java values and invoke
1090 * X11InputMethod.dispatchComposedText().
1091 *
1092 * client_data: X11InputMethod object
1093 */
1094 static void
1095 PreeditDrawCallback(XIC ic, XPointer client_data,
1096 XIMPreeditDrawCallbackStruct *pre_draw)
1097 {
1098 JNIEnv *env = GetJNIEnv();
1099 X11InputMethodData *pX11IMData = NULL;
1100 jmethodID x11imMethodID;
1101
1102 XIMText *text;
1103 jstring javastr = NULL;
1104 jintArray style = NULL;
1105
1170 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
1171 "dispatchComposedText",
1172 "(Ljava/lang/String;[IIIIJ)V",
1173 javastr,
1174 style,
1175 (jint)pre_draw->chg_first,
1176 (jint)pre_draw->chg_length,
1177 (jint)pre_draw->caret,
1178 awt_util_nowMillisUTC());
1179 finally:
1180 AWT_UNLOCK();
1181 return;
1182 }
1183
1184 static void
1185 PreeditCaretCallback(XIC ic, XPointer client_data,
1186 XIMPreeditCaretCallbackStruct *pre_caret)
1187 {
1188 /*ARGSUSED*/
1189 /* printf("Native: PreeditCaretCallback\n"); */
1190
1191 }
1192
1193 #if defined(__linux__) || defined(MACOSX)
1194 static void
1195 StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1196 {
1197 /*ARGSUSED*/
1198 /*printf("StatusStartCallback:\n"); */
1199
1200 }
1201
1202 static void
1203 StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1204 {
1205 /*ARGSUSED*/
1206 /*printf("StatusDoneCallback:\n"); */
1207
1208 }
1209
1210 static void
1211 StatusDrawCallback(XIC ic, XPointer client_data,
1212 XIMStatusDrawCallbackStruct *status_draw)
1213 {
1214 /*ARGSUSED*/
1215 /*printf("StatusDrawCallback:\n"); */
1216 JNIEnv *env = GetJNIEnv();
1217 X11InputMethodData *pX11IMData = NULL;
1218 StatusWindow *statusWindow;
1219
1220 AWT_LOCK();
1221
1222 if (!isX11InputMethodGRefInList((jobject)client_data)) {
1223 if ((jobject)client_data == currentX11InputMethodInstance) {
1224 currentX11InputMethodInstance = NULL;
1225 }
1226 goto finally;
1227 }
1228
1229 if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data))
1230 || NULL == (statusWindow = pX11IMData->statusWindow)){
1231 goto finally;
1232 }
1233 currentX11InputMethodInstance = (jobject)client_data;
1234
1235 if (status_draw->type == XIMTextType){
1236 XIMText *text = (status_draw->data).text;
1237 if (text != NULL){
1238 if (text->string.multi_byte != NULL) {
1239 strncpy(statusWindow->status, text->string.multi_byte, MAX_STATUS_LEN);
1240 statusWindow->status[MAX_STATUS_LEN - 1] = '\0';
1241 }
1242 else {
1243 char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1244 strncpy(statusWindow->status, mbstr, MAX_STATUS_LEN);
1245 statusWindow->status[MAX_STATUS_LEN - 1] = '\0';
1246 }
1247 statusWindow->on = True;
1248 onoffStatusWindow(pX11IMData, statusWindow->parent, True);
1249 paintStatusWindow(statusWindow);
1250 }
1251 else {
1252 statusWindow->on = False;
1253 /*just turnoff the status window
1254 paintStatusWindow(statusWindow);
1255 */
1256 onoffStatusWindow(pX11IMData, 0, False);
1257 }
1258 }
1259
1260 finally:
1261 AWT_UNLOCK();
1262 }
1263 #endif /* __linux__ || MACOSX */
1264
1265 static void CommitStringCallback(XIC ic, XPointer client_data, XPointer call_data) {
1266 JNIEnv *env = GetJNIEnv();
1267 XIMText * text = (XIMText *)call_data;
1268 X11InputMethodData *pX11IMData = NULL;
1269 jstring javastr;
1270
1271 AWT_LOCK();
1310
1311 X11im = XOpenIM(display, NULL, NULL, NULL);
1312 if (X11im == NULL) {
1313 return;
1314 }
1315
1316 ximCallback.callback = (XIMProc)DestroyXIMCallback;
1317 ximCallback.client_data = NULL;
1318 XSetIMValues(X11im, XNDestroyCallback, &ximCallback, NULL);
1319 }
1320
1321 static void DestroyXIMCallback(XIM im, XPointer client_data, XPointer call_data) {
1322 /* mark that XIM server was destroyed */
1323 X11im = NULL;
1324 JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1325 /* free the old pX11IMData and set it to null. this also avoids crashing
1326 * the jvm if the XIM server reappears */
1327 X11InputMethodData *pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
1328 }
1329
1330 /*
1331 * Class: sun_awt_X11InputMethod
1332 * Method: initIDs
1333 * Signature: ()V
1334 */
1335
1336 /* This function gets called from the static initializer for
1337 X11InputMethod.java
1338 to initialize the fieldIDs for fields that may be accessed from C */
1339 JNIEXPORT void JNICALL
1340 Java_sun_awt_X11InputMethod_initIDs(JNIEnv *env, jclass cls)
1341 {
1342 x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J");
1343 }
1344
1345
1346 JNIEXPORT jboolean JNICALL
1347 Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env,
1348 jobject this,
1349 jlong display)
1350 {
1351 Bool registered;
1352
1353 AWT_LOCK();
1354
1355 dpy = (Display *)jlong_to_ptr(display);
1356
1357 /* Use IMInstantiate call back only on Linux, as there is a bug in Solaris
1358 (4768335)
1359 */
1360 #if defined(__linux__) || defined(MACOSX)
1361 registered = XRegisterIMInstantiateCallback(dpy, NULL, NULL,
1362 NULL, (XIDProc)OpenXIMCallback, NULL);
1363 if (!registered) {
1364 /* directly call openXIM callback */
1365 #endif
1366 OpenXIMCallback(dpy, NULL, NULL);
1367 #if defined(__linux__) || defined(MACOSX)
1368 }
1369 #endif
1370
1371 AWT_UNLOCK();
1372
1373 return JNI_TRUE;
1374 }
1375
1376 JNIEXPORT jboolean JNICALL
1377 Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env,
1378 jobject this,
1379 jlong window)
1380 {
1381 X11InputMethodData *pX11IMData;
1382 jobject globalRef;
1383 XIC ic;
1384
1385 AWT_LOCK();
1386
1387 if (!window) {
1388 JNU_ThrowNullPointerException(env, "NullPointerException");
1389 AWT_UNLOCK();
1390 return JNI_FALSE;
1391 }
1392
1393 pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData));
1394 if (pX11IMData == NULL) {
1395 THROW_OUT_OF_MEMORY_ERROR();
1396 AWT_UNLOCK();
1397 return JNI_FALSE;
1398 }
1399
1406 pX11IMData->lookup_buf = 0;
1407 pX11IMData->lookup_buf_len = 0;
1408
1409 if (createXIC(env, pX11IMData, (Window)window) == False) {
1410 destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData);
1411 pX11IMData = (X11InputMethodData *) NULL;
1412 if ((*env)->ExceptionCheck(env)) {
1413 goto finally;
1414 }
1415 }
1416
1417 setX11InputMethodData(env, this, pX11IMData);
1418
1419 finally:
1420 AWT_UNLOCK();
1421 return (pX11IMData != NULL);
1422 }
1423
1424 JNIEXPORT void JNICALL
1425 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env,
1426 jobject this,
1427 jlong w,
1428 jboolean req,
1429 jboolean active)
1430 {
1431 X11InputMethodData *pX11IMData;
1432 AWT_LOCK();
1433 pX11IMData = getX11InputMethodData(env, this);
1434 if (pX11IMData == NULL) {
1435 AWT_UNLOCK();
1436 return;
1437 }
1438
1439 if (req) {
1440 if (!w) {
1441 AWT_UNLOCK();
1442 return;
1443 }
1444 pX11IMData->current_ic = active ?
1445 pX11IMData->ic_active : pX11IMData->ic_passive;
1446 /*
1447 * On Solaris2.6, setXICWindowFocus() has to be invoked
1448 * before setting focus.
1449 */
1454 #if defined(__linux__) || defined(MACOSX)
1455 if (active && pX11IMData->statusWindow && pX11IMData->statusWindow->on)
1456 onoffStatusWindow(pX11IMData, w, True);
1457 #endif
1458 } else {
1459 currentX11InputMethodInstance = NULL;
1460 currentFocusWindow = 0;
1461 #if defined(__linux__) || defined(MACOSX)
1462 onoffStatusWindow(pX11IMData, 0, False);
1463 if (pX11IMData->current_ic != NULL)
1464 #endif
1465 setXICFocus(pX11IMData->current_ic, req);
1466
1467 pX11IMData->current_ic = (XIC)0;
1468 }
1469
1470 XFlush(dpy);
1471 AWT_UNLOCK();
1472 }
1473
1474 JNIEXPORT void JNICALL
1475 Java_sun_awt_X11InputMethod_turnoffStatusWindow(JNIEnv *env,
1476 jobject this)
1477 {
1478 #if defined(__linux__) || defined(MACOSX)
1479 X11InputMethodData *pX11IMData;
1480 StatusWindow *statusWindow;
1481
1482 AWT_LOCK();
1483
1484 if (NULL == currentX11InputMethodInstance
1485 || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
1486 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
1487 || NULL == (statusWindow = pX11IMData->statusWindow)
1488 || !statusWindow->on ){
1489 AWT_UNLOCK();
1490 return;
1491 }
1492 onoffStatusWindow(pX11IMData, 0, False);
1493
1494 AWT_UNLOCK();
1495 #endif
1496 }
1497
1498 JNIEXPORT void JNICALL
1499 Java_sun_awt_X11InputMethod_disposeXIC(JNIEnv *env,
1500 jobject this)
1501 {
1502 X11InputMethodData *pX11IMData = NULL;
1503
1504 AWT_LOCK();
1505 pX11IMData = getX11InputMethodData(env, this);
1506 if (pX11IMData == NULL) {
1507 AWT_UNLOCK();
1508 return;
1509 }
1510
1511 setX11InputMethodData(env, this, NULL);
1512
1513 if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) {
1514 currentX11InputMethodInstance = NULL;
1515 currentFocusWindow = 0;
1516 }
1517 destroyX11InputMethodData(env, pX11IMData);
1518 AWT_UNLOCK();
1519 }
1520
1521 JNIEXPORT jstring JNICALL
1522 Java_sun_awt_X11InputMethod_resetXIC(JNIEnv *env,
1523 jobject this)
1524 {
1525 X11InputMethodData *pX11IMData;
1526 char *xText = NULL;
1527 jstring jText = (jstring)0;
1528
1529 AWT_LOCK();
1530 pX11IMData = getX11InputMethodData(env, this);
1531 if (pX11IMData == NULL) {
1532 AWT_UNLOCK();
1533 return jText;
1534 }
1535
1536 if (pX11IMData->current_ic)
1537 xText = XmbResetIC(pX11IMData->current_ic);
1538 else {
1539 /*
1540 * If there is no reference to the current XIC, try to reset both XICs.
1541 */
1542 xText = XmbResetIC(pX11IMData->ic_active);
1543 /*it may also means that the real client component does
1547 */
1548 setXICFocus(pX11IMData->ic_active, FALSE);
1549 if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1550 char *tmpText = XmbResetIC(pX11IMData->ic_passive);
1551 setXICFocus(pX11IMData->ic_passive, FALSE);
1552 if (xText == (char *)NULL && tmpText)
1553 xText = tmpText;
1554 }
1555
1556 }
1557 if (xText != NULL) {
1558 jText = JNU_NewStringPlatform(env, (const char *)xText);
1559 XFree((void *)xText);
1560 }
1561
1562 AWT_UNLOCK();
1563 return jText;
1564 }
1565
1566 /*
1567 * Class: sun_awt_X11InputMethod
1568 * Method: setCompositionEnabledNative
1569 * Signature: (ZJ)V
1570 *
1571 * This method tries to set the XNPreeditState attribute associated with the current
1572 * XIC to the passed in 'enable' state.
1573 *
1574 * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the
1575 * 'enable' state; Otherwise, if XSetICValues fails to set this attribute,
1576 * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this
1577 * method fails due to other reasons.
1578 *
1579 */
1580 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_setCompositionEnabledNative
1581 (JNIEnv *env, jobject this, jboolean enable)
1582 {
1583 X11InputMethodData *pX11IMData;
1584 char * ret = NULL;
1585
1586 AWT_LOCK();
1587 pX11IMData = getX11InputMethodData(env, this);
1588
1589 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1590 AWT_UNLOCK();
1591 return JNI_FALSE;
1592 }
1593
1594 ret = XSetICValues(pX11IMData->current_ic, XNPreeditState,
1595 (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL);
1596 AWT_UNLOCK();
1597
1598 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1599 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1600 }
1601
1602 return (jboolean)(ret == 0);
1603 }
1604
1605 /*
1606 * Class: sun_awt_X11InputMethod
1607 * Method: isCompositionEnabledNative
1608 * Signature: (J)Z
1609 *
1610 * This method tries to get the XNPreeditState attribute associated with the current XIC.
1611 *
1612 * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if
1613 * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException
1614 * will be thrown. JNI_FALSE is returned if this method fails due to other reasons.
1615 *
1616 */
1617 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_isCompositionEnabledNative
1618 (JNIEnv *env, jobject this)
1619 {
1620 X11InputMethodData *pX11IMData = NULL;
1621 char * ret = NULL;
1622 XIMPreeditState state;
1623
1624 AWT_LOCK();
1625 pX11IMData = getX11InputMethodData(env, this);
1626
1627 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1628 AWT_UNLOCK();
1629 return JNI_FALSE;
1630 }
1631
1632 ret = XGetICValues(pX11IMData->current_ic, XNPreeditState, &state, NULL);
1633 AWT_UNLOCK();
1634
1635 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1636 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1637 return JNI_FALSE;
|
1 /*
2 * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #ifdef HEADLESS
27 #error This file should not be included in headless library
28 #endif
29
30 #include "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 void PreeditStartCallback(XIC, XPointer, XPointer);
50 static void PreeditDoneCallback(XIC, XPointer, XPointer);
51 static void PreeditDrawCallback(XIC, XPointer,
52 XIMPreeditDrawCallbackStruct *);
53 static void PreeditCaretCallback(XIC, XPointer,
54 XIMPreeditCaretCallbackStruct *);
55 #if defined(__linux__) || defined(MACOSX)
56 static void StatusStartCallback(XIC, XPointer, XPointer);
57 static void StatusDoneCallback(XIC, XPointer, XPointer);
58 static void StatusDrawCallback(XIC, XPointer,
59 XIMStatusDrawCallbackStruct *);
60 #endif
61
519 mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf,
520 pX11IMData->lookup_buf_len - 1, &keysym, &status);
521 }
522 pX11IMData->lookup_buf[mblen] = 0;
523
524 /* Get keysym without taking modifiers into account first to map
525 * to AWT keyCode table.
526 */
527 switch (status) {
528 case XLookupBoth:
529 if (!composing) {
530 if (event->keycode != 0) {
531 *keysymp = keysym;
532 result = False;
533 break;
534 }
535 }
536 composing = False;
537 /*FALLTHRU*/
538 case XLookupChars:
539 /*
540 printf("lookupString: status=XLookupChars, type=%d, state=%x, keycode=%x, keysym=%x\n",
541 event->type, event->state, event->keycode, keysym);
542 */
543 javastr = JNU_NewStringPlatform(env, (const char *)pX11IMData->lookup_buf);
544 if (javastr != NULL) {
545 JNU_CallMethodByName(env, NULL,
546 currentX11InputMethodInstance,
547 "dispatchCommittedText",
548 "(Ljava/lang/String;J)V",
549 javastr,
550 event->time);
551 }
552 break;
553
554 case XLookupKeySym:
555 /*
556 printf("lookupString: status=XLookupKeySym, type=%d, state=%x, keycode=%x, keysym=%x\n",
557 event->type, event->state, event->keycode, keysym);
558 */
559 if (keysym == XK_Multi_key)
560 composing = True;
561 if (! composing) {
562 *keysymp = keysym;
563 result = False;
564 }
565 break;
566
567 case XLookupNone:
568 /*
569 printf("lookupString: status=XLookupNone, type=%d, state=%x, keycode=%x, keysym=%x\n",
570 event->type, event->state, event->keycode, keysym);
571 */
572 break;
573 }
574
575 return result;
576 }
577
578 #if defined(__linux__) || defined(MACOSX)
579 static StatusWindow *createStatusWindow(Window parent) {
580 StatusWindow *statusWindow;
581 XSetWindowAttributes attrib;
582 unsigned long attribmask;
583 Window containerWindow;
584 Window status;
585 Window child;
586 XWindowAttributes xwa;
587 XWindowAttributes xxwa;
588 /* Variable for XCreateFontSet()*/
589 char **mclr;
590 int mccr = 0;
591 char *dsr;
592 unsigned long bg, fg, light, dim;
593 int x, y, off_x, off_y, xx, yy;
594 unsigned int w, h, bw, depth;
595 XGCValues values;
596 unsigned long valuemask = 0; /*ignore XGCvalue and use defaults*/
597 int screen = 0;
598 int i;
599 AwtGraphicsConfigDataPtr adata;
600 extern int awt_numScreens;
601 /*hardcode the size right now, should get the size base on font*/
602 int width=80, height=22;
603 Window rootWindow;
604 Window *ignoreWindowPtr;
605 unsigned int ignoreUnit;
606
607 XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth);
608
609 attrib.override_redirect = True;
610 attribmask = CWOverrideRedirect;
611 for (i = 0; i < awt_numScreens; i++) {
612 if (RootWindow(dpy, i) == rootWindow) {
613 screen = i;
614 break;
615 }
616 }
617 adata = getDefaultConfig(screen);
618 bg = adata->AwtColorMatch(255, 255, 255, adata);
619 fg = adata->AwtColorMatch(0, 0, 0, adata);
620 light = adata->AwtColorMatch(195, 195, 195, adata);
621 dim = adata->AwtColorMatch(128, 128, 128, adata);
622
634 &ignoreWindowPtr,
635 &ignoreUnit);
636 XGetWindowAttributes(dpy, containerWindow, &xxwa);
637
638 off_x = (xxwa.width - xwa.width) / 2;
639 off_y = xxwa.height - xwa.height - off_x; /*it's magic:-) */
640
641 /*get the size of root window*/
642 XGetWindowAttributes(dpy, rootWindow, &xxwa);
643
644 XTranslateCoordinates(dpy,
645 parent, xwa.root,
646 xwa.x, xwa.y,
647 &x, &y,
648 &child);
649 xx = x - off_x;
650 yy = y + xwa.height - off_y;
651 if (xx < 0 ){
652 xx = 0;
653 }
654 if (xx + width > xxwa.width) {
655 xx = xxwa.width - width;
656 }
657 if (yy + height > xxwa.height) {
658 yy = xxwa.height - height;
659 }
660
661 status = XCreateWindow(dpy,
662 xwa.root,
663 xx, yy,
664 width, height,
665 0,
666 xwa.depth,
667 InputOutput,
668 adata->awt_visInfo.visual,
669 attribmask, &attrib);
670 XSelectInput(dpy, status,
671 ExposureMask | StructureNotifyMask | EnterWindowMask |
672 LeaveWindowMask | VisibilityChangeMask);
673 statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow));
674 if (statusWindow == NULL){
675 THROW_OUT_OF_MEMORY_ERROR();
676 return NULL;
677 }
706 statusWindow->bgGC = XCreateGC(dpy, status, valuemask, &values);
707 XSetForeground(dpy, statusWindow->bgGC, bg);
708 return statusWindow;
709 }
710
711 /* This method is to turn off or turn on the status window. */
712 static void onoffStatusWindow(X11InputMethodData* pX11IMData,
713 Window parent,
714 Bool ON){
715 XWindowAttributes xwa;
716 Window child;
717 int x, y;
718 StatusWindow *statusWindow = NULL;
719
720 if (NULL == currentX11InputMethodInstance ||
721 NULL == pX11IMData ||
722 NULL == (statusWindow = pX11IMData->statusWindow)){
723 return;
724 }
725
726 if (ON == False) {
727 XUnmapWindow(dpy, statusWindow->w);
728 statusWindow->on = False;
729 return;
730 }
731 parent = JNU_CallMethodByName(GetJNIEnv(), NULL, pX11IMData->x11inputmethod,
732 "getCurrentParentWindow",
733 "()J").j;
734 if (statusWindow->parent != parent) {
735 statusWindow->parent = parent;
736 }
737 XGetWindowAttributes(dpy, parent, &xwa);
738 XTranslateCoordinates(dpy,
739 parent, xwa.root,
740 xwa.x, xwa.y,
741 &x, &y,
742 &child);
743 if (statusWindow->x != x ||
744 statusWindow->y != y ||
745 statusWindow->height != xwa.height)
746 {
747 statusWindow->x = x;
748 statusWindow->y = y;
749 statusWindow->height = xwa.height;
750 x = statusWindow->x - statusWindow->off_x;
751 y = statusWindow->y + statusWindow->height - statusWindow->off_y;
752 if (x < 0 ) {
753 x = 0;
754 }
755 if (x + statusWindow->statusW > statusWindow->rootW) {
756 x = statusWindow->rootW - statusWindow->statusW;
757 }
758 if (y + statusWindow->statusH > statusWindow->rootH) {
759 y = statusWindow->rootH - statusWindow->statusH;
760 }
761 XMoveWindow(dpy, statusWindow->w, x, y);
762 }
763 statusWindow->on = True;
764 XMapWindow(dpy, statusWindow->w);
765 }
766
767 void paintStatusWindow(StatusWindow *statusWindow){
768 Window win = statusWindow->w;
769 GC lightgc = statusWindow->lightGC;
770 GC dimgc = statusWindow->dimGC;
771 GC bggc = statusWindow->bgGC;
772 GC fggc = statusWindow->fgGC;
773
774 int width = statusWindow->statusW;
775 int height = statusWindow->statusH;
776 int bwidth = statusWindow->bWidth;
777 XFillRectangle(dpy, win, bggc, 0, 0, width, height);
778 /* draw border */
779 XDrawLine(dpy, win, fggc, 0, 0, width, 0);
780 XDrawLine(dpy, win, fggc, 0, height-1, width-1, height-1);
781 XDrawLine(dpy, win, fggc, 0, 0, 0, height-1);
782 XDrawLine(dpy, win, fggc, width-1, 0, width-1, height-1);
783
784 XDrawLine(dpy, win, lightgc, 1, 1, width-bwidth, 1);
785 XDrawLine(dpy, win, lightgc, 1, 1, 1, height-2);
786 XDrawLine(dpy, win, lightgc, 1, height-2, width-bwidth, height-2);
787 XDrawLine(dpy, win, lightgc, width-bwidth-1, 1, width-bwidth-1, height-2);
788
789 XDrawLine(dpy, win, dimgc, 2, 2, 2, height-3);
790 XDrawLine(dpy, win, dimgc, 2, height-3, width-bwidth-1, height-3);
791 XDrawLine(dpy, win, dimgc, 2, 2, width-bwidth-2, 2);
792 XDrawLine(dpy, win, dimgc, width-bwidth, 2, width-bwidth, height-3);
793 if (statusWindow->fontset) {
794 XmbDrawString(dpy, win, statusWindow->fontset, fggc,
795 bwidth + 2, height - bwidth - 4,
796 statusWindow->status,
797 strlen(statusWindow->status));
798 } else {
799 /*too bad we failed to create a fontset for this locale*/
800 XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4,
801 "[InputMethod ON]", strlen("[InputMethod ON]"));
802 }
803 }
804
805 static void adjustStatusWindow(Window shell) {
806 JNIEnv *env = GetJNIEnv();
807 X11InputMethodData *pX11IMData = NULL;
808 StatusWindow *statusWindow;
809
810 if (NULL == currentX11InputMethodInstance
811 || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
812 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
813 || NULL == (statusWindow = pX11IMData->statusWindow)
814 || !statusWindow->on)
815 {
816 return;
817 }
818
819 {
820 XWindowAttributes xwa;
821 int x, y;
822 Window child;
823 XGetWindowAttributes(dpy, shell, &xwa);
824 XTranslateCoordinates(dpy,
825 shell, xwa.root,
826 xwa.x, xwa.y,
827 &x, &y,
828 &child);
829 if (statusWindow->x != x
830 || statusWindow->y != y
831 || statusWindow->height != xwa.height){
832 statusWindow->x = x;
833 statusWindow->y = y;
834 statusWindow->height = xwa.height;
835
836 x = statusWindow->x - statusWindow->off_x;
837 y = statusWindow->y + statusWindow->height - statusWindow->off_y;
838 if (x < 0 ) {
839 x = 0;
840 }
841 if (x + statusWindow->statusW > statusWindow->rootW){
842 x = statusWindow->rootW - statusWindow->statusW;
843 }
844 if (y + statusWindow->statusH > statusWindow->rootH){
845 y = statusWindow->rootH - statusWindow->statusH;
846 }
847 XMoveWindow(dpy, statusWindow->w, x, y);
848 }
849 }
850 }
851 #endif /* __linux__ || MACOSX */
852
853 /*
854 * Creates two XICs, one for active clients and the other for passive
855 * clients. All information on those XICs are stored in the
856 * X11InputMethodData given by the pX11IMData parameter.
857 *
858 * For active clients: Try to use preedit callback to support
859 * on-the-spot. If tc is not null, the XIC to be created will
860 * share the Status Area with Motif widgets (TextComponents). If the
861 * preferable styles can't be used, fallback to root-window styles. If
862 * root-window styles failed, fallback to None styles.
863 *
864 * For passive clients: Try to use root-window styles. If failed,
865 * fallback to None styles.
866 */
867 static Bool
868 createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w)
869 {
870 XVaNestedList preedit = NULL;
871 XVaNestedList status = NULL;
872 XIMStyle on_the_spot_styles = XIMPreeditCallbacks,
875 no_styles = 0;
876 XIMCallback *callbacks;
877 unsigned short i;
878 XIMStyles *im_styles;
879 char *ret = NULL;
880
881 if (X11im == NULL) {
882 return False;
883 }
884 if (!w) {
885 return False;
886 }
887
888 ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL);
889
890 if (ret != NULL) {
891 jio_fprintf(stderr,"XGetIMValues: %s\n",ret);
892 return FALSE ;
893 }
894
895 on_the_spot_styles |= XIMStatusNothing;
896
897 #if defined(__linux__) || defined(MACOSX)
898 /*kinput does not support XIMPreeditCallbacks and XIMStatusArea
899 at the same time, so use StatusCallback to draw the status
900 ourself
901 */
902 for (i = 0; i < im_styles->count_styles; i++) {
903 if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) {
904 on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks);
905 break;
906 }
907 }
908 #endif /* __linux__ || MACOSX */
909
910 for (i = 0; i < im_styles->count_styles; i++) {
911 active_styles |= im_styles->supported_styles[i] & on_the_spot_styles;
912 passive_styles |= im_styles->supported_styles[i] & ROOT_WINDOW_STYLES;
913 no_styles |= im_styles->supported_styles[i] & NO_STYLES;
914 }
915
916 XFree(im_styles);
917
918 if (active_styles != on_the_spot_styles) {
919 if (passive_styles == ROOT_WINDOW_STYLES)
920 active_styles = passive_styles;
921 else {
922 if (no_styles == NO_STYLES)
923 active_styles = passive_styles = NO_STYLES;
924 else
925 active_styles = passive_styles = 0;
926 }
927 } else {
965 status = (XVaNestedList)XVaCreateNestedList(0,
966 XNStatusStartCallback, &callbacks[StatusStartIndex],
967 XNStatusDoneCallback, &callbacks[StatusDoneIndex],
968 XNStatusDrawCallback, &callbacks[StatusDrawIndex],
969 NULL);
970
971 if (status == NULL)
972 goto err;
973 pX11IMData->statusWindow = createStatusWindow(w);
974 pX11IMData->ic_active = XCreateIC(X11im,
975 XNClientWindow, w,
976 XNFocusWindow, w,
977 XNInputStyle, active_styles,
978 XNPreeditAttributes, preedit,
979 XNStatusAttributes, status,
980 NULL);
981 XFree((void *)status);
982 XFree((void *)preedit);
983 }
984 #else /* !__linux__ && !MACOSX */
985 pX11IMData->ic_active = XCreateIC(X11im,
986 XNClientWindow, w,
987 XNFocusWindow, w,
988 XNInputStyle, active_styles,
989 XNPreeditAttributes, preedit,
990 NULL);
991 XFree((void *)preedit);
992 #endif /* __linux__ || MACOSX */
993 } else {
994 pX11IMData->ic_active = XCreateIC(X11im,
995 XNClientWindow, w,
996 XNFocusWindow, w,
997 XNInputStyle, active_styles,
998 NULL);
999 pX11IMData->ic_passive = pX11IMData->ic_active;
1000 }
1001
1002 if (pX11IMData->ic_active == (XIC)0
1003 || pX11IMData->ic_passive == (XIC)0) {
1004 return False;
1005 }
1006
1007 /*
1008 * Use commit string call back if possible.
1009 * This will ensure the correct order of preedit text and commit text
1010 */
1017 XSetICValues (pX11IMData->ic_passive, XNCommitStringCallback, &cb, NULL);
1018 }
1019 }
1020
1021 /* Add the global reference object to X11InputMethod to the list. */
1022 addToX11InputMethodGRefList(pX11IMData->x11inputmethod);
1023
1024 return True;
1025
1026 err:
1027 if (preedit)
1028 XFree((void *)preedit);
1029 THROW_OUT_OF_MEMORY_ERROR();
1030 return False;
1031 }
1032
1033 static void
1034 PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1035 {
1036 /*ARGSUSED*/
1037 /* printf("Native: PreeditStartCallback\n"); */
1038 }
1039
1040 static void
1041 PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1042 {
1043 /*ARGSUSED*/
1044 /* printf("Native: PreeditDoneCallback\n"); */
1045 }
1046
1047 /*
1048 * Translate the preedit draw callback items to Java values and invoke
1049 * X11InputMethod.dispatchComposedText().
1050 *
1051 * client_data: X11InputMethod object
1052 */
1053 static void
1054 PreeditDrawCallback(XIC ic, XPointer client_data,
1055 XIMPreeditDrawCallbackStruct *pre_draw)
1056 {
1057 JNIEnv *env = GetJNIEnv();
1058 X11InputMethodData *pX11IMData = NULL;
1059 jmethodID x11imMethodID;
1060
1061 XIMText *text;
1062 jstring javastr = NULL;
1063 jintArray style = NULL;
1064
1129 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
1130 "dispatchComposedText",
1131 "(Ljava/lang/String;[IIIIJ)V",
1132 javastr,
1133 style,
1134 (jint)pre_draw->chg_first,
1135 (jint)pre_draw->chg_length,
1136 (jint)pre_draw->caret,
1137 awt_util_nowMillisUTC());
1138 finally:
1139 AWT_UNLOCK();
1140 return;
1141 }
1142
1143 static void
1144 PreeditCaretCallback(XIC ic, XPointer client_data,
1145 XIMPreeditCaretCallbackStruct *pre_caret)
1146 {
1147 /*ARGSUSED*/
1148 /* printf("Native: PreeditCaretCallback\n"); */
1149 }
1150
1151 #if defined(__linux__) || defined(MACOSX)
1152 static void
1153 StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1154 {
1155 /*ARGSUSED*/
1156 /*printf("StatusStartCallback:\n"); */
1157 }
1158
1159 static void
1160 StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1161 {
1162 /*ARGSUSED*/
1163 /*printf("StatusDoneCallback:\n"); */
1164 }
1165
1166 static void
1167 StatusDrawCallback(XIC ic, XPointer client_data,
1168 XIMStatusDrawCallbackStruct *status_draw)
1169 {
1170 /*ARGSUSED*/
1171 /*printf("StatusDrawCallback:\n"); */
1172 JNIEnv *env = GetJNIEnv();
1173 X11InputMethodData *pX11IMData = NULL;
1174 StatusWindow *statusWindow;
1175
1176 AWT_LOCK();
1177
1178 if (!isX11InputMethodGRefInList((jobject)client_data)) {
1179 if ((jobject)client_data == currentX11InputMethodInstance) {
1180 currentX11InputMethodInstance = NULL;
1181 }
1182 goto finally;
1183 }
1184
1185 if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data))
1186 || NULL == (statusWindow = pX11IMData->statusWindow)){
1187 goto finally;
1188 }
1189 currentX11InputMethodInstance = (jobject)client_data;
1190
1191 if (status_draw->type == XIMTextType) {
1192 XIMText *text = (status_draw->data).text;
1193 if (text != NULL) {
1194 if (text->string.multi_byte != NULL) {
1195 strncpy(statusWindow->status, text->string.multi_byte, MAX_STATUS_LEN);
1196 statusWindow->status[MAX_STATUS_LEN - 1] = '\0';
1197 } else {
1198 char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1199 strncpy(statusWindow->status, mbstr, MAX_STATUS_LEN);
1200 statusWindow->status[MAX_STATUS_LEN - 1] = '\0';
1201 }
1202 statusWindow->on = True;
1203 onoffStatusWindow(pX11IMData, statusWindow->parent, True);
1204 paintStatusWindow(statusWindow);
1205 } else {
1206 statusWindow->on = False;
1207 /*just turnoff the status window
1208 paintStatusWindow(statusWindow);
1209 */
1210 onoffStatusWindow(pX11IMData, 0, False);
1211 }
1212 }
1213
1214 finally:
1215 AWT_UNLOCK();
1216 }
1217 #endif /* __linux__ || MACOSX */
1218
1219 static void CommitStringCallback(XIC ic, XPointer client_data, XPointer call_data) {
1220 JNIEnv *env = GetJNIEnv();
1221 XIMText * text = (XIMText *)call_data;
1222 X11InputMethodData *pX11IMData = NULL;
1223 jstring javastr;
1224
1225 AWT_LOCK();
1264
1265 X11im = XOpenIM(display, NULL, NULL, NULL);
1266 if (X11im == NULL) {
1267 return;
1268 }
1269
1270 ximCallback.callback = (XIMProc)DestroyXIMCallback;
1271 ximCallback.client_data = NULL;
1272 XSetIMValues(X11im, XNDestroyCallback, &ximCallback, NULL);
1273 }
1274
1275 static void DestroyXIMCallback(XIM im, XPointer client_data, XPointer call_data) {
1276 /* mark that XIM server was destroyed */
1277 X11im = NULL;
1278 JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1279 /* free the old pX11IMData and set it to null. this also avoids crashing
1280 * the jvm if the XIM server reappears */
1281 X11InputMethodData *pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
1282 }
1283
1284 JNIEXPORT jboolean JNICALL
1285 Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env,
1286 jobject this,
1287 jlong display)
1288 {
1289 Bool registered;
1290
1291 AWT_LOCK();
1292
1293 dpy = (Display *)jlong_to_ptr(display);
1294
1295 /* Use IMInstantiate call back only on Linux, as there is a bug in Solaris
1296 (4768335)
1297 */
1298 #if defined(__linux__) || defined(MACOSX)
1299 registered = XRegisterIMInstantiateCallback(dpy, NULL, NULL,
1300 NULL, (XIDProc)OpenXIMCallback, NULL);
1301 if (!registered) {
1302 /* directly call openXIM callback */
1303 #endif
1304 OpenXIMCallback(dpy, NULL, NULL);
1305 #if defined(__linux__) || defined(MACOSX)
1306 }
1307 #endif
1308
1309 AWT_UNLOCK();
1310
1311 return JNI_TRUE;
1312 }
1313
1314 JNIEXPORT jboolean JNICALL
1315 Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env,
1316 jobject this,
1317 jlong window)
1318 {
1319 X11InputMethodData *pX11IMData;
1320 jobject globalRef;
1321 XIC ic;
1322
1323 AWT_LOCK();
1324
1325 if (!window) {
1326 JNU_ThrowNullPointerException(env, "NullPointerException");
1327 AWT_UNLOCK();
1328 return JNI_FALSE;
1329 }
1330
1331 pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData));
1332 if (pX11IMData == NULL) {
1333 THROW_OUT_OF_MEMORY_ERROR();
1334 AWT_UNLOCK();
1335 return JNI_FALSE;
1336 }
1337
1344 pX11IMData->lookup_buf = 0;
1345 pX11IMData->lookup_buf_len = 0;
1346
1347 if (createXIC(env, pX11IMData, (Window)window) == False) {
1348 destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData);
1349 pX11IMData = (X11InputMethodData *) NULL;
1350 if ((*env)->ExceptionCheck(env)) {
1351 goto finally;
1352 }
1353 }
1354
1355 setX11InputMethodData(env, this, pX11IMData);
1356
1357 finally:
1358 AWT_UNLOCK();
1359 return (pX11IMData != NULL);
1360 }
1361
1362 JNIEXPORT void JNICALL
1363 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env,
1364 jobject this,
1365 jlong w,
1366 jboolean req,
1367 jboolean active)
1368 {
1369 X11InputMethodData *pX11IMData;
1370 AWT_LOCK();
1371 pX11IMData = getX11InputMethodData(env, this);
1372 if (pX11IMData == NULL) {
1373 AWT_UNLOCK();
1374 return;
1375 }
1376
1377 if (req) {
1378 if (!w) {
1379 AWT_UNLOCK();
1380 return;
1381 }
1382 pX11IMData->current_ic = active ?
1383 pX11IMData->ic_active : pX11IMData->ic_passive;
1384 /*
1385 * On Solaris2.6, setXICWindowFocus() has to be invoked
1386 * before setting focus.
1387 */
1392 #if defined(__linux__) || defined(MACOSX)
1393 if (active && pX11IMData->statusWindow && pX11IMData->statusWindow->on)
1394 onoffStatusWindow(pX11IMData, w, True);
1395 #endif
1396 } else {
1397 currentX11InputMethodInstance = NULL;
1398 currentFocusWindow = 0;
1399 #if defined(__linux__) || defined(MACOSX)
1400 onoffStatusWindow(pX11IMData, 0, False);
1401 if (pX11IMData->current_ic != NULL)
1402 #endif
1403 setXICFocus(pX11IMData->current_ic, req);
1404
1405 pX11IMData->current_ic = (XIC)0;
1406 }
1407
1408 XFlush(dpy);
1409 AWT_UNLOCK();
1410 }
1411
1412 /*
1413 * Class: sun_awt_X11InputMethodBase
1414 * Method: initIDs
1415 * Signature: ()V
1416 * This function gets called from the static initializer for
1417 * X11InputMethod.java to initialize the fieldIDs for fields
1418 * that may be accessed from C
1419 */
1420 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_initIDs
1421 (JNIEnv *env, jclass cls)
1422 {
1423 x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J");
1424 }
1425
1426 /*
1427 * Class: sun_awt_X11InputMethodBase
1428 * Method: turnoffStatusWindow
1429 * Signature: ()V
1430 */
1431 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_turnoffStatusWindow
1432 (JNIEnv *env, jobject this)
1433 {
1434 #if defined(__linux__) || defined(MACOSX)
1435 X11InputMethodData *pX11IMData;
1436 StatusWindow *statusWindow;
1437
1438 AWT_LOCK();
1439
1440 if (NULL == currentX11InputMethodInstance
1441 || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
1442 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
1443 || NULL == (statusWindow = pX11IMData->statusWindow)
1444 || !statusWindow->on ){
1445 AWT_UNLOCK();
1446 return;
1447 }
1448 onoffStatusWindow(pX11IMData, 0, False);
1449
1450 AWT_UNLOCK();
1451 #endif
1452 }
1453
1454 /*
1455 * Class: sun_awt_X11InputMethodBase
1456 * Method: disposeXIC
1457 * Signature: ()V
1458 */
1459 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_disposeXIC
1460 (JNIEnv *env, jobject this)
1461 {
1462 X11InputMethodData *pX11IMData = NULL;
1463
1464 AWT_LOCK();
1465 pX11IMData = getX11InputMethodData(env, this);
1466 if (pX11IMData == NULL) {
1467 AWT_UNLOCK();
1468 return;
1469 }
1470
1471 setX11InputMethodData(env, this, NULL);
1472
1473 if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) {
1474 currentX11InputMethodInstance = NULL;
1475 currentFocusWindow = 0;
1476 }
1477 destroyX11InputMethodData(env, pX11IMData);
1478 AWT_UNLOCK();
1479 }
1480
1481 /*
1482 * Class: sun_awt_X11InputMethodBase
1483 * Method: resetXIC
1484 * Signature: ()Ljava/lang/String;
1485 */
1486 JNIEXPORT jstring JNICALL Java_sun_awt_X11InputMethodBase_resetXIC
1487 (JNIEnv *env, jobject this)
1488 {
1489 X11InputMethodData *pX11IMData;
1490 char *xText = NULL;
1491 jstring jText = (jstring)0;
1492
1493 AWT_LOCK();
1494 pX11IMData = getX11InputMethodData(env, this);
1495 if (pX11IMData == NULL) {
1496 AWT_UNLOCK();
1497 return jText;
1498 }
1499
1500 if (pX11IMData->current_ic)
1501 xText = XmbResetIC(pX11IMData->current_ic);
1502 else {
1503 /*
1504 * If there is no reference to the current XIC, try to reset both XICs.
1505 */
1506 xText = XmbResetIC(pX11IMData->ic_active);
1507 /*it may also means that the real client component does
1511 */
1512 setXICFocus(pX11IMData->ic_active, FALSE);
1513 if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1514 char *tmpText = XmbResetIC(pX11IMData->ic_passive);
1515 setXICFocus(pX11IMData->ic_passive, FALSE);
1516 if (xText == (char *)NULL && tmpText)
1517 xText = tmpText;
1518 }
1519
1520 }
1521 if (xText != NULL) {
1522 jText = JNU_NewStringPlatform(env, (const char *)xText);
1523 XFree((void *)xText);
1524 }
1525
1526 AWT_UNLOCK();
1527 return jText;
1528 }
1529
1530 /*
1531 * Class: sun_awt_X11InputMethodBase
1532 * Method: setCompositionEnabledNative
1533 * Signature: (Z)Z
1534 *
1535 * This method tries to set the XNPreeditState attribute associated with the current
1536 * XIC to the passed in 'enable' state.
1537 *
1538 * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the
1539 * 'enable' state; Otherwise, if XSetICValues fails to set this attribute,
1540 * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this
1541 * method fails due to other reasons.
1542 */
1543 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethodBase_setCompositionEnabledNative
1544 (JNIEnv *env, jobject this, jboolean enable)
1545 {
1546 X11InputMethodData *pX11IMData;
1547 char * ret = NULL;
1548
1549 AWT_LOCK();
1550 pX11IMData = getX11InputMethodData(env, this);
1551
1552 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1553 AWT_UNLOCK();
1554 return JNI_FALSE;
1555 }
1556
1557 ret = XSetICValues(pX11IMData->current_ic, XNPreeditState,
1558 (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL);
1559 AWT_UNLOCK();
1560
1561 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1562 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1563 }
1564
1565 return (jboolean)(ret == 0);
1566 }
1567
1568 /*
1569 * Class: sun_awt_X11InputMethodBase
1570 * Method: isCompositionEnabledNative
1571 * Signature: ()Z
1572 *
1573 * This method tries to get the XNPreeditState attribute associated with the current XIC.
1574 *
1575 * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if
1576 * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException
1577 * will be thrown. JNI_FALSE is returned if this method fails due to other reasons.
1578 */
1579 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethodBase_isCompositionEnabledNative
1580 (JNIEnv *env, jobject this)
1581 {
1582 X11InputMethodData *pX11IMData = NULL;
1583 char * ret = NULL;
1584 XIMPreeditState state;
1585
1586 AWT_LOCK();
1587 pX11IMData = getX11InputMethodData(env, this);
1588
1589 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1590 AWT_UNLOCK();
1591 return JNI_FALSE;
1592 }
1593
1594 ret = XGetICValues(pX11IMData->current_ic, XNPreeditState, &state, NULL);
1595 AWT_UNLOCK();
1596
1597 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1598 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1599 return JNI_FALSE;
|