1 /*
2  * Author:	Yoichiro Ueno (ueno@cs.titech.ac.jp)
3  *
4  * Copyright (C) 1991, 1992, Yoichiro Ueno.
5  *
6  * Permission to use, copy, modify, and distribute this software and
7  * its documentation for any purpose is hereby granted by the Author without
8  * fee, provided that the above copyright notice appear in all copies and
9  * that both the copyright notice and this permission notice appear in
10  * supporting documentation, and that the name of the Author not be used
11  * in advertising or publicity pertaining to distribution of the software
12  * without specific, written prior permission.  The Author makes no
13  * representations about the suitability of this software for any purpose.
14  * It is provided "as is" without express or implied warranty.
15  *
16  * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
20  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
21  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  *
24  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/convxim.c,v 1.5 2009/08/07 03:41:16 william Exp $
25  */
26 #ifndef _NO_XIM
27 
28 #define _INCLUDE_FROM_CONVXIM_C_
29 
30 #include "tgifdefs.h"
31 
32 #include "convkinput.e"
33 #include "convxim.e"
34 #include "dialog.e"
35 #include "font.e"
36 #include "list.e"
37 #include "miniline.e"
38 #include "msg.e"
39 #include "setup.e"
40 #include "strtbl.e"
41 #include "util.e"
42 
43 #ifndef _NO_XIMP
44 #define DEFAULT_MODIFIERS	""
45 #define DEFAULT_LANG		"ja_JP.EUC"
46 #else /* _NO_XIMP */
47 #define DEFAULT_MODIFIERS	"@im=_XWNMO"
48 #define DEFAULT_LANG		"ja_JP.ujis"
49 #endif /* ~_NO_XIMP */
50 
51 typedef struct tagXICInfo {
52    XIC ic;
53    Window win;
54 } XICInfo;
55 
56 static CVList gXICInfoList;
57 
58 char	ximConvModifiers[MAXSTRING] = DEFAULT_MODIFIERS;
59 char	ximConvLang[MAXSTRING] = DEFAULT_LANG;
60 
61 static char	*locale = NULL;
62 static char	*modifiers = NULL;
63 static XIM	im = NULL;
64 static XIC	ic = NULL;
65 
66 typedef void (MYIOErrHandler)ARGS_DECL((void));
67 
68 static MYIOErrHandler	*oldhandler = NULL;
69 static Bool		_XIMErrorFlag = False;
70 static Bool		overthespot = False;
71 
72 static Bool	modscim = False;
73 static int	pre_x = 0;
74 static int	pre_y = 0;
75 
76 #ifndef _NO_XIMP
_XipSetIOErrorHandler(new_handler)77 static MYIOErrHandler *_XipSetIOErrorHandler(new_handler)
78     MYIOErrHandler *new_handler;
79 {
80     return NULL;
81 }
82 #else /* _NO_XIMP */
83 extern void	(*_XipSetIOErrorHandler())();
84 #endif /* ~_NO_XIMP */
85 
86 /* --------------------- Utility Functions --------------------- */
87 
88 static
FindXIC(win)89 CVListElem *FindXIC(win)
90    Window win;
91 {
92     CVListElem *pElem=NULL;
93 
94     for (pElem=ListFirst(&gXICInfoList); pElem != NULL;
95             pElem=ListNext(&gXICInfoList, pElem)) {
96         XICInfo *pxi=(XICInfo*)(pElem->obj);
97 
98         if (pxi->win == win) {
99            return pElem;
100         }
101     }
102     return NULL;
103 }
104 
105 static
DeleteXICInfo(pElem)106 void DeleteXICInfo(pElem)
107     CVListElem *pElem;
108 {
109     XICInfo *pxi=(XICInfo*)(pElem->obj);
110 
111     if (pxi->ic != NULL) XDestroyIC(pxi->ic);
112 
113     ListUnlink(&gXICInfoList, pElem);
114     free(pElem);
115 }
116 
117 /* --------------------- Exported Functions --------------------- */
118 
119 static
_XIMIOError()120 void _XIMIOError()
121 {
122     _XIMErrorFlag = True;
123 }
124 
125 static
XIMClose(win)126 void XIMClose(win)
127    Window win;
128 {
129     CVListElem *pElem=FindXIC(win);
130 
131     if (pElem != NULL) {
132         DeleteXICInfo(pElem);
133     }
134 }
135 
136 #define ROOT 1
137 #define OVERTHESPOT 2
138 static int style_type=ROOT;
139 XFontSet XIMfs;
140 XFontSetExtents * fs_ext=NULL;
141 char** missing_list=NULL;
142 int missing_count=0;
143 char* def_string=NULL;
144 char* XIMFontSetStr="-misc-fixed-medium-r-normal--14-*";
145 
146 static
XIMSetLocale()147 void XIMSetLocale()
148 {
149 #ifndef _NO_LOCALE_SUPPORT
150     char buf[80], *c_ptr=NULL;
151 
152     c_ptr = (char*)getenv("LC_ALL");
153     if (c_ptr != NULL) {
154         UtilStrCpyN(ximConvLang, sizeof(ximConvLang), c_ptr);
155     } else {
156         c_ptr = (char*)getenv("LANG");
157         if (c_ptr != NULL) {
158             UtilStrCpyN(ximConvLang, sizeof(ximConvLang), c_ptr);
159         } else if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME, "Lang")) !=
160                 NULL) {
161             UtilTrimBlanks(c_ptr);
162             UtilStrCpyN(ximConvLang, sizeof(ximConvLang), c_ptr);
163         }
164     }
165     locale = setlocale(LC_ALL, ximConvLang);
166     sprintf(buf, TgLoadString(STID_LOCALE_IS),
167             locale==NULL ? TgLoadCachedString(CSTID_PARANED_NULL) : locale);
168     Msg(buf);
169 
170     c_ptr = (char*)getenv("LC_CTYPE");
171     if (c_ptr != NULL) {
172         UtilStrCpyN(buf, sizeof(buf), c_ptr);
173         locale = setlocale(LC_CTYPE, buf);
174 #ifdef _TGIF_DBG /* debug, do not translate */
175         sprintf(buf, "LC_CTYPE is '%s'.", locale==NULL ? "null" : locale);
176         Msg(buf);
177 #endif /* _TGIF_DBG */
178     }
179     setlocale(LC_NUMERIC, "C");
180 #endif /* ~_NO_LOCALE_SUPPORT */
181 }
182 
XIMSetICFocus(dpy,win)183 void XIMSetICFocus(dpy, win)
184     Display *dpy;
185     Window win;
186 {
187     char	buf[80];
188     XIMStyles *    styles=NULL;
189     Bool	style_flag;
190     int		style_attr=0;
191     int	i;
192     XPoint spot;
193     XRectangle s_rect;
194     XVaNestedList preedit_attr, status_attr;
195     CVListElem *pElem=NULL;
196 
197     if(oldhandler == NULL)
198 	oldhandler = _XipSetIOErrorHandler(_XIMIOError);
199 
200     if(locale == NULL) {
201         XIMSetLocale();
202     }
203     if(modifiers == NULL) {
204 	char *c_ptr=(char*)getenv("XMODIFIERS");
205 
206 	if (c_ptr != NULL) {
207 	    UtilStrCpyN(ximConvModifiers, sizeof(ximConvModifiers), c_ptr);
208 	} else {
209             if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME, "Modifiers")) !=
210                     NULL) {
211 	        UtilTrimBlanks(c_ptr);
212 	        UtilStrCpyN(ximConvModifiers, sizeof(ximConvModifiers), c_ptr);
213             }
214 	}
215 	modifiers = XSetLocaleModifiers(ximConvModifiers);
216 	sprintf(buf, TgLoadString(STID_MODIFIER_IS),
217 		modifiers==NULL ? TgLoadCachedString(CSTID_PARANED_NULL) :
218 		modifiers);
219 	Msg(buf);
220     }
221 
222     for (i = 0; i <= (int)strlen(modifiers) - 4 ; i++) {
223         if (strncmp((char *)&modifiers[i], "SCIM", 4) == 0 ||
224                 strncmp((char *)&modifiers[i], "scim", 4) == 0) {
225             modscim = True;
226             break;
227         }
228     }
229 
230     if(im == NULL) {
231 	im = XOpenIM(mainDisplay, NULL, NULL, NULL);
232 	if(im == NULL) {
233 	    MsgBox(TgLoadString(STID_CANNOT_OPEN_XIM), TOOL_NAME, INFO_MB);
234 	    return;
235 	}
236     }
237     pElem = FindXIC(win);
238     if (pElem != NULL) {
239         XICInfo *pxi=(XICInfo*)(pElem->obj);
240 
241         ic = pxi->ic;
242     } else {
243         XICInfo *pxi=(XICInfo*)malloc(sizeof(XICInfo));
244 
245         if (pxi == NULL) FailAllocMessage();
246         memset(pxi, 0, sizeof(XICInfo));
247         if (!ListAppend(&gXICInfoList, pxi)) {
248         }
249         pxi->win = win;
250 
251 	XGetIMValues(im,
252 		XNQueryInputStyle, &styles,
253 		NULL, NULL);
254 	style_flag = False;
255 	if (overthespot) {
256 	  for(i = 0; i < (int)(styles->count_styles); i ++){
257 	    if((styles->supported_styles[i] ==
258 	       (XIMPreeditPosition | XIMStatusArea)) ||
259                (styles->supported_styles[i] ==
260                (XIMPreeditPosition | XIMStatusNothing))){
261 	      style_flag = True;
262 	      style_type = OVERTHESPOT;
263 	      style_attr = styles->supported_styles[i];
264 	      Msg(TgLoadString(STID_OVERTHESPOT_CONV));
265 	    }
266 	  }
267 	}else{
268 	  for(i = 0; i < (int)(styles->count_styles); i ++){
269 	    if(styles->supported_styles[i] ==
270 	       (XIMPreeditNothing | XIMStatusNothing)){
271 	      style_flag = True;
272 	      style_type = ROOT;
273 	      Msg(TgLoadString(STID_ROOT_CONV));
274 	    }
275 	  }
276 	}
277 	if(!style_flag) {
278 	    sprintf(gszMsgBox, TgLoadString(STID_IM_NOT_SUPPORT_GIVEN_STYLE),
279 	          (overthespot ? "OverTheSpot" : "Root"));
280 	    MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
281 	    XCloseIM(im);
282 	    im = NULL;
283 	    return;
284 	}
285 	switch (style_type){
286 	case ROOT:
287 	ic = XCreateIC(im,
288 		XNInputStyle , XIMPreeditNothing | XIMStatusNothing,
289 		XNClientWindow, win,
290 		XNFocusWindow, win,
291 		NULL, NULL);
292 	break;
293 	case OVERTHESPOT:
294 	XIMfs=XCreateFontSet(dpy, XIMFontSetStr,
295 			  &missing_list, &missing_count, &def_string);
296 	fs_ext=XExtentsOfFontSet(XIMfs);
297 	spot.x=0; spot.y=fs_ext->max_logical_extent.height;
298 	s_rect.x=0; s_rect.y=fs_ext->max_logical_extent.height;
299 	s_rect.width=640; s_rect.height=fs_ext->max_logical_extent.height;
300 	preedit_attr=XVaCreateNestedList(0,
301 					 XNSpotLocation, &spot,
302 					 XNFontSet, XIMfs,
303 					 NULL);
304 	status_attr=XVaCreateNestedList(0,
305 					XNArea, &s_rect,
306 					XNFontSet, XIMfs,
307 					NULL);
308 	ic = XCreateIC(im,
309 	        XNInputStyle , style_attr,
310 		XNClientWindow, win,
311 		XNFocusWindow, win,
312 		XNPreeditAttributes, preedit_attr,
313 		XNStatusAttributes, status_attr,
314 		NULL, NULL);
315 	XFree(preedit_attr);
316 	XFree(status_attr);
317 	break;
318 	}
319 	if(ic == NULL) {
320 	    fprintf(stderr, "%s\n",
321 		TgLoadString(STID_FAIL_TO_CREATE_INPUTCONTEXT));
322 	    XCloseIM(im);
323 	    im = NULL;
324 	    return;
325 	}
326 	pxi->ic = ic;
327 	Msg(TgLoadString(STID_OPEN_XIM));
328     }
329     XSetICFocus(ic);
330 
331     if(_XIMErrorFlag) {
332 	XIMClose(win);
333 	Msg(TgLoadString(STID_CLOSE_XIM));
334     }
335 }
336 
XIMNextEvent(dpy,win,xev_p)337 void XIMNextEvent(dpy, win, xev_p)
338 Display *	dpy;
339 Window		win;
340 XEvent *	xev_p;
341 {
342     Bool	filter_status;
343 
344     do {
345 	XNextEvent(dpy, xev_p);
346 
347 	/*
348 	 * The 2nd argument has been changed from win to None
349 	 *         according to Ambrose Li's investigation.  See his
350 	 *         e-mail on "Sun, 09 Mar 2003 19:09:38 EST".
351 	 */
352 	filter_status = XFilterEvent(xev_p, None);
353 
354 	if(_XIMErrorFlag) {
355 	    XIMClose(win);
356 	    Msg(TgLoadString(STID_CLOSE_XIM));
357 	}
358     } while(filter_status == True);
359 }
360 
XIMLookupString(key_ev,buf,buf_len,key_sym_p,c_stat_p)361 int XIMLookupString(key_ev, buf, buf_len, key_sym_p, c_stat_p)
362 XKeyEvent *	key_ev;
363 char *		buf;
364 int		buf_len;
365 KeySym *	key_sym_p;
366 XIMStatus *	c_stat_p;
367 {
368     int has_ch=0;
369 
370     if(im && ic) {
371 	c_stat_p->valid = MB_STATUS;
372 	has_ch = XmbLookupString (ic, key_ev, buf, buf_len, key_sym_p, &c_stat_p->mb_status);
373 /*
374  *      switch (c_stat_p->mb_status) {
375  *      case XLookupKeySym:
376  *      case XLookupBoth:
377  *          {
378  *              unsigned int key_sym=(unsigned int)(*key_sym_p);
379  *
380  *              if (key_sym < 0x100) {
381  *                 has_ch = 1;
382  *                 *buf = (char)(unsigned char)(key_sym & 0x0ff);
383  *                 buf[1] = '\0';
384  *              }
385  *          }
386  *          break;
387  *      default: break;
388  *      }
389  */
390     }
391     else {
392 	c_stat_p->valid = COMPOSE_STATUS;
393 	has_ch = XLookupString (key_ev, buf, buf_len, key_sym_p, &c_stat_p->status);
394     }
395     return has_ch;
396 }
397 
XIMUnsetICFocus(win)398 void XIMUnsetICFocus(win)
399     Window win;
400 {
401     CVListElem *pElem=FindXIC(win);
402 
403     if (pElem != NULL) {
404         XICInfo *pxi=(XICInfo*)(pElem->obj);
405 
406         ic = pxi->ic;
407     }
408     if(im && ic) {
409 	XUnsetICFocus(ic);
410     }
411 }
412 
XIMSetConvOverSpot(gnOverTheSpot)413 void XIMSetConvOverSpot(gnOverTheSpot)
414 Bool gnOverTheSpot;
415 {
416   overthespot=gnOverTheSpot;
417 }
418 
XIMTellCursorPosition(dpy,win,x,y)419 void XIMTellCursorPosition(dpy, win, x, y)
420 Display* dpy;
421 Window win;
422 int x;
423 int y;
424 {
425   XPoint spot;
426   XRectangle s_rect;
427   XVaNestedList preedit_attr,status_attr;
428   char     szAttemptedFontName[MAXSTRING+1];
429   CVListElem *pElem=FindXIC(win);
430 
431   if (pElem != NULL) {
432     XICInfo *pxi=(XICInfo*)(pElem->obj);
433 
434     ic = pxi->ic;
435   }
436   if (im == NULL || ic == NULL || !overthespot) return;
437 
438   if (x == pre_x && y == pre_y) return;
439   pre_x = x; pre_y = y;
440 
441   if (XIMfs) XFreeFontSet(dpy, XIMfs);
442   GetCurFontInfoStr(szAttemptedFontName, sizeof(szAttemptedFontName));
443   XIMfs=XCreateFontSet(dpy, szAttemptedFontName,
444 		    &missing_list, &missing_count, &def_string);
445   fs_ext=XExtentsOfFontSet(XIMfs);
446   spot.x=textCurX; spot.y=textCurBaselineY;
447   s_rect.x=textCurX; s_rect.y=textCurBaselineY+3;
448   /*s_rect.width=200; s_rect.height=fs_ext->max_logical_extent.height;*/
449   s_rect.width=50; s_rect.height=16;
450 
451   preedit_attr=XVaCreateNestedList(0,
452 				   XNSpotLocation, &spot,
453 				   XNFontSet, XIMfs,
454 				   NULL);
455   status_attr=XVaCreateNestedList(0,
456 				  XNArea, &s_rect,
457 				  NULL);
458   XSetICValues(ic,
459 	       XNPreeditAttributes, preedit_attr,
460 	       XNStatusAttributes, status_attr,
461 	       NULL);
462   XFree(preedit_attr);
463   XFree(status_attr);
464   if (!modscim) {
465     XSetICFocus(ic);
466   }
467 }
468 
XIMCleanUp()469 void XIMCleanUp()
470 {
471   CVListElem *pElem=NULL;
472 
473   for (pElem=ListFirst(&gXICInfoList); pElem != NULL;
474       pElem=ListNext(&gXICInfoList, pElem)) {
475     XICInfo *pxi=(XICInfo*)(pElem->obj);
476 
477     if (pxi->ic != NULL) XDestroyIC(pxi->ic);
478     free(pxi);
479   }
480   ListUnlinkAll(&gXICInfoList);
481 
482   if(im != NULL) {
483     XCloseIM(im);
484   }
485   im = NULL;
486   ic = NULL;
487   _XIMErrorFlag = False;
488 }
489 
XIMInit()490 int XIMInit()
491 {
492   im = NULL;
493   ic = NULL;
494   _XIMErrorFlag = False;
495   CVListInit(&gXICInfoList);
496 
497   return TRUE;
498 }
499 
500 #endif /* ~_NO_XIM */
501 
502