imDefLkup.c revision 3b4ba46c
1/******************************************************************
2
3           Copyright 1992, 1993, 1994 by FUJITSU LIMITED
4
5Permission to use, copy, modify, distribute, and sell this software
6and its documentation for any purpose is hereby granted without fee,
7provided that the above copyright notice appear in all copies and
8that both that copyright notice and this permission notice appear
9in supporting documentation, and that the name of FUJITSU LIMITED
10not be used in advertising or publicity pertaining to distribution
11of the software without specific, written prior permission.
12FUJITSU LIMITED makes no representations about the suitability of
13this software for any purpose.
14It is provided "as is" without express or implied warranty.
15
16FUJITSU LIMITED DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18EVENT SHALL FUJITSU LIMITED BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
20USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
21OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22PERFORMANCE OF THIS SOFTWARE.
23
24  Author: Takashi Fujiwara     FUJITSU LIMITED
25                               fujiwara@a80.tech.yk.fujitsu.co.jp
26
27******************************************************************/
28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include <X11/Xatom.h>
33#include "Xlibint.h"
34#include "Xlcint.h"
35#include "Ximint.h"
36
37Xic
38_XimICOfXICID(
39    Xim		  im,
40    XICID	  icid)
41{
42    Xic		  pic;
43
44    for (pic = (Xic)im->core.ic_chain; pic; pic = (Xic)pic->core.next) {
45	if (pic->private.proto.icid == icid)
46	    return pic;
47    }
48    return (Xic)0;
49}
50
51static void
52_XimProcIMSetEventMask(
53    Xim		 im,
54    XPointer	 buf)
55{
56    EVENTMASK	*buf_l = (EVENTMASK *)buf;
57
58    im->private.proto.forward_event_mask     = buf_l[0];
59    im->private.proto.synchronous_event_mask = buf_l[1];
60    return;
61}
62
63static void
64_XimProcICSetEventMask(
65    Xic		 ic,
66    XPointer	 buf)
67{
68    EVENTMASK	*buf_l = (EVENTMASK *)buf;
69
70    ic->private.proto.forward_event_mask     = buf_l[0];
71    ic->private.proto.synchronous_event_mask = buf_l[1];
72    _XimReregisterFilter(ic);
73    return;
74}
75
76Bool
77_XimSetEventMaskCallback(
78    Xim		 xim,
79    INT16	 len,
80    XPointer	 data,
81    XPointer	 call_data)
82{
83    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
84    XIMID        imid = buf_s[0];
85    XICID        icid = buf_s[1];
86    Xim		 im = (Xim)call_data;
87    Xic		 ic;
88
89    if (imid == im->private.proto.imid) {
90	if (icid) {
91	    if (!(ic = _XimICOfXICID(im, icid)))
92		return False;
93	    _XimProcICSetEventMask(ic, (XPointer)&buf_s[2]);
94	} else {
95	    _XimProcIMSetEventMask(im, (XPointer)&buf_s[2]);
96	}
97	return True;
98    }
99    return False;
100}
101
102static Bool
103_XimSyncCheck(
104    Xim          im,
105    INT16        len,
106    XPointer	 data,
107    XPointer     arg)
108{
109    Xic		 ic  = (Xic)arg;
110    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
111    CARD8	 major_opcode = *((CARD8 *)data);
112    CARD8	 minor_opcode = *((CARD8 *)data + 1);
113    XIMID	 imid = buf_s[0];
114    XICID	 icid = buf_s[1];
115
116    if ((major_opcode == XIM_SYNC_REPLY)
117     && (minor_opcode == 0)
118     && (imid == im->private.proto.imid)
119     && (icid == ic->private.proto.icid))
120	return True;
121    if ((major_opcode == XIM_ERROR)
122     && (minor_opcode == 0)
123     && (buf_s[2] & XIM_IMID_VALID)
124     && (imid == im->private.proto.imid)
125     && (buf_s[2] & XIM_ICID_VALID)
126     && (icid == ic->private.proto.icid))
127	return True;
128    return False;
129}
130
131Bool
132_XimSync(
133    Xim		 im,
134    Xic		 ic)
135{
136    CARD32	 buf32[BUFSIZE/4];
137    CARD8	*buf = (CARD8 *)buf32;
138    CARD16	*buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
139    INT16	 len;
140    CARD32	 reply32[BUFSIZE/4];
141    char	*reply = (char *)reply32;
142    XPointer	 preply;
143    int		 buf_size;
144    int		 ret_code;
145
146    buf_s[0] = im->private.proto.imid;		/* imid */
147    buf_s[1] = ic->private.proto.icid;		/* icid */
148
149    len = sizeof(CARD16)			/* sizeof imid */
150	+ sizeof(CARD16);			/* sizeof icid */
151
152    _XimSetHeader((XPointer)buf, XIM_SYNC, 0, &len);
153    if (!(_XimWrite(im, len, (XPointer)buf)))
154	return False;
155    _XimFlush(im);
156    buf_size = BUFSIZE;
157    ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
158					_XimSyncCheck, (XPointer)ic);
159    if(ret_code == XIM_TRUE) {
160	preply = reply;
161    } else if(ret_code == XIM_OVERFLOW) {
162	if(len <= 0) {
163	    preply = reply;
164	} else {
165	    buf_size = len;
166	    preply = Xmalloc(len);
167	    ret_code = _XimRead(im, &len, preply, buf_size,
168					_XimSyncCheck, (XPointer)ic);
169	    if(ret_code != XIM_TRUE) {
170		Xfree(preply);
171		return False;
172	    }
173	}
174    } else {
175	return False;
176    }
177    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
178    if (*((CARD8 *)preply) == XIM_ERROR) {
179	_XimProcError(im, 0, (XPointer)&buf_s[3]);
180	if(reply != preply)
181	    Xfree(preply);
182	return False;
183    }
184    if(reply != preply)
185	Xfree(preply);
186    return True;
187}
188
189Bool
190_XimProcSyncReply(
191    Xim		 im,
192    Xic		 ic)
193{
194    CARD32	 buf32[BUFSIZE/4];
195    CARD8	*buf = (CARD8 *)buf32;
196    CARD16	*buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
197    INT16	 len;
198
199    buf_s[0] = im->private.proto.imid;		/* imid */
200    buf_s[1] = ic->private.proto.icid;		/* icid */
201
202    len = sizeof(CARD16)			/* sizeof imid */
203	+ sizeof(CARD16);			/* sizeof icid */
204
205    _XimSetHeader((XPointer)buf, XIM_SYNC_REPLY, 0, &len);
206    if (!(_XimWrite(im, len, (XPointer)buf)))
207	return False;
208    _XimFlush(im);
209    return True;
210}
211
212Bool
213_XimRespSyncReply(
214    Xic		 ic,
215    BITMASK16	 mode)
216{
217    if (mode & XimSYNCHRONUS) /* SYNC Request */
218	MARK_NEED_SYNC_REPLY(ic->core.im);
219
220    return True;
221}
222
223Bool
224_XimSyncCallback(
225    Xim		 xim,
226    INT16	 len,
227    XPointer	 data,
228    XPointer	 call_data)
229{
230    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
231    XIMID        imid = buf_s[0];
232    XICID        icid = buf_s[1];
233    Xim		 im = (Xim)call_data;
234    Xic		 ic;
235
236    if ((imid == im->private.proto.imid)
237     && (ic = _XimICOfXICID(im, icid))) {
238	(void)_XimProcSyncReply(im, ic);
239	return True;
240    }
241    return False;
242}
243
244static INT16
245_XimSetEventToWire(
246    XEvent	*ev,
247    xEvent	*event)
248{
249    if (!(_XimProtoEventToWire(ev, event, False)))
250	return 0;
251    event->u.u.sequenceNumber =
252		((XAnyEvent *)ev)->serial & (unsigned long)0xffff;
253    return sz_xEvent;
254}
255
256static Bool
257_XimForwardEventCore(
258    Xic		 ic,
259    XEvent	*ev,
260    Bool	 sync)
261{
262    Xim		 im = (Xim)ic->core.im;
263    CARD32	 buf32[BUFSIZE/4];
264    CARD8	*buf = (CARD8 *)buf32;
265    CARD16	*buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
266    CARD32	 reply32[BUFSIZE/4];
267    char	*reply = (char *)reply32;
268    XPointer	 preply;
269    int		 buf_size;
270    int		 ret_code;
271    INT16	 len;
272
273    bzero(buf32, sizeof(buf32)); /* valgrind noticed uninitialized memory use! */
274
275    if (!(len = _XimSetEventToWire(ev, (xEvent *)&buf_s[4])))
276	return False;				/* X event */
277
278    buf_s[0] = im->private.proto.imid;		/* imid */
279    buf_s[1] = ic->private.proto.icid;		/* icid */
280    buf_s[2] = sync ? XimSYNCHRONUS : 0;	/* flag */
281    buf_s[3] =
282        (CARD16)((((XAnyEvent *)ev)->serial & ~((unsigned long)0xffff)) >> 16);
283						/* serial number */
284
285    len += sizeof(CARD16)			/* sizeof imid */
286	 + sizeof(CARD16)			/* sizeof icid */
287	 + sizeof(BITMASK16)			/* sizeof flag */
288	 + sizeof(CARD16);			/* sizeof serila number */
289
290    _XimSetHeader((XPointer)buf, XIM_FORWARD_EVENT, 0, &len);
291    if (!(_XimWrite(im, len, (XPointer)buf)))
292	return False;
293    _XimFlush(im);
294
295    if (sync) {
296	buf_size = BUFSIZE;
297	ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
298					_XimSyncCheck, (XPointer)ic);
299	if(ret_code == XIM_TRUE) {
300	    preply = reply;
301	} else if(ret_code == XIM_OVERFLOW) {
302	    if(len <= 0) {
303		preply = reply;
304	    } else {
305		buf_size = len;
306		preply = Xmalloc(len);
307		ret_code = _XimRead(im, &len, preply, buf_size,
308					_XimSyncCheck, (XPointer)ic);
309		if(ret_code != XIM_TRUE) {
310		    Xfree(preply);
311		    return False;
312		}
313	    }
314	} else {
315	    return False;
316	}
317	buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
318	if (*((CARD8 *)preply) == XIM_ERROR) {
319	    _XimProcError(im, 0, (XPointer)&buf_s[3]);
320	    if(reply != preply)
321		Xfree(preply);
322	    return False;
323	}
324	if(reply != preply)
325	    Xfree(preply);
326    }
327    return True;
328}
329
330Bool
331_XimForwardEvent(
332    Xic		 ic,
333    XEvent	*ev,
334    Bool	 sync)
335{
336#ifdef EXT_FORWARD
337    if (((ev->type == KeyPress) || (ev->type == KeyRelease)))
338	if (_XimExtForwardKeyEvent(ic, (XKeyEvent *)ev, sync))
339	    return True;
340#endif
341    return _XimForwardEventCore(ic, ev, sync);
342}
343
344Bool
345_XimFabricateSerial(
346    Xim			 im,
347    XKeyEvent		*event)
348{
349    /* GTK2 XIM module sets serial=0. */
350    if (!event->serial || !im->private.proto.enable_fabricated_order) {
351	MARK_FABRICATED(im);
352	return True;
353    }
354    if (event->serial == im->private.proto.fabricated_serial) {
355	fprintf(stderr, "%s,%d: The key event is already fabricated.\n", __FILE__, __LINE__);
356	return False;
357    }
358    if (im->private.proto.fabricated_serial)
359	fprintf(stderr, "%s,%d: Tried to fabricate a wrong key event.\n", __FILE__, __LINE__);
360
361    MARK_FABRICATED(im);
362    im->private.proto.fabricated_serial = event->serial;
363    im->private.proto.fabricated_time = event->time;
364    return True;
365}
366
367Bool
368_XimUnfabricateSerial(
369    Xim			 im,
370    Xic			 ic,
371    XKeyEvent		*event)
372{
373    if (!im->private.proto.enable_fabricated_order) {
374	UNMARK_FABRICATED(im);
375	return True;
376    }
377    /* GTK2 XIM module sets serial=0. */
378    if (!event->serial) {
379	/* _XimCommitRecv() sets event->serial and call _XimFabricateSerial()
380	 * but GTK2 XIM always reset event->serial=0 with XFilterEvent().
381	 */
382	if (ic && ic->private.proto.commit_info)
383	    im->private.proto.fabricated_serial = 0;
384	UNMARK_FABRICATED(im);
385	return True;
386    }
387    if (!im->private.proto.fabricated_serial) {
388	fprintf(stderr, "%s,%d: The key event is already unfabricated.\n", __FILE__, __LINE__);
389	return False;
390    }
391    if (event->serial != im->private.proto.fabricated_serial)
392	fprintf(stderr, "%s,%d: Tried to unfabricate a wrong key event.\n", __FILE__, __LINE__);
393
394    im->private.proto.fabricated_serial = 0;
395    im->private.proto.fabricated_time = 0;
396    UNMARK_FABRICATED(im);
397    return True;
398}
399
400Bool
401_XimIsFabricatedSerial(
402    Xim			 im,
403    XKeyEvent		*event)
404{
405    /* GTK2 XIM module sets serial=0. */
406    if (!event->serial || !im->private.proto.enable_fabricated_order)
407	return IS_FABRICATED(im) ? True : False;
408    if (event->serial == im->private.proto.fabricated_serial)
409	return True;
410    if (!im->private.proto.fabricated_serial)
411	return False;
412    /* Rotate time */
413    if (event->time < im->private.proto.fabricated_time) {
414	if (event->time >= 1000)
415	    im->private.proto.fabricated_time = 0;
416    } else if (event->time - im->private.proto.fabricated_time > 1000) {
417	fprintf(stderr,
418	        "%s,%d: The application disposed a key event with %ld serial.\n",
419	        __FILE__, __LINE__,
420	        im->private.proto.fabricated_serial);
421	im->private.proto.enable_fabricated_order = False;
422	if (IS_FABRICATED(im)) {
423	    if (event->serial)
424		im->private.proto.fabricated_serial = event->serial;
425	    return True;
426	}
427    }
428    return False;
429}
430
431static void
432_XimProcEvent(
433    Display		*d,
434    Xic			 ic,
435    XEvent		*ev,
436    CARD16		*buf)
437{
438    INT16	 serial = buf[0];
439    xEvent	*xev = (xEvent *)&buf[1];
440
441    _XimProtoWireToEvent(ev, xev, False);
442    ev->xany.serial |= serial << 16;
443    ev->xany.send_event = False;
444    ev->xany.display = d;
445    _XimFabricateSerial((Xim)ic->core.im, &ev->xkey);
446    return;
447}
448
449static Bool
450_XimForwardEventRecv(
451    Xim		 im,
452    Xic		 ic,
453    XPointer	 buf)
454{
455    CARD16	*buf_s = (CARD16 *)buf;
456    Display	*d = im->core.display;
457    XEvent	 ev;
458
459    _XimProcEvent(d, ic, &ev, &buf_s[1]);
460
461    (void)_XimRespSyncReply(ic, buf_s[0]);
462
463    XPutBackEvent(d, &ev);
464
465    return True;
466}
467
468Bool
469_XimForwardEventCallback(
470    Xim		 xim,
471    INT16	 len,
472    XPointer	 data,
473    XPointer	 call_data)
474{
475    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
476    XIMID        imid = buf_s[0];
477    XICID        icid = buf_s[1];
478    Xim		 im = (Xim)call_data;
479    Xic		 ic;
480
481    if ((imid == im->private.proto.imid)
482     && (ic = _XimICOfXICID(im, icid))) {
483	(void)_XimForwardEventRecv(im, ic, (XPointer)&buf_s[2]);
484	return True;
485    }
486    return False;
487}
488
489static Bool
490_XimRegisterTriggerkey(
491    Xim			 im,
492    XPointer		 buf)
493{
494    CARD32		*buf_l = (CARD32 *)buf;
495    CARD32		 len;
496    CARD32 		*key;
497
498    if (IS_DYNAMIC_EVENT_FLOW(im))	/* already Dynamic event flow mode */
499	return True;
500
501    /*
502     *  register onkeylist
503     */
504
505    len = buf_l[0];				/* length of on-keys */
506    len += sizeof(INT32);			/* sizeof length of on-keys */
507
508    if (!(key = Xmalloc(len))) {
509	_XimError(im, 0, XIM_BadAlloc, (INT16)0, (CARD16)0, (char *)NULL);
510	return False;
511    }
512    memcpy((char *)key, (char *)buf_l, len);
513    im->private.proto.im_onkeylist = key;
514
515    MARK_DYNAMIC_EVENT_FLOW(im);
516
517    /*
518     *  register offkeylist
519     */
520
521    buf_l = (CARD32 *)((char *)buf + len);
522    len = buf_l[0];				/* length of off-keys */
523    len += sizeof(INT32);			/* sizeof length of off-keys */
524
525    if (!(key = Xmalloc(len))) {
526	_XimError(im, 0, XIM_BadAlloc, (INT16)0, (CARD16)0, (char *)NULL);
527	return False;
528    }
529
530    memcpy((char *)key, (char *)buf_l, len);
531    im->private.proto.im_offkeylist = key;
532
533    return True;
534}
535
536Bool
537_XimRegisterTriggerKeysCallback(
538    Xim		 xim,
539    INT16	 len,
540    XPointer	 data,
541    XPointer	 call_data)
542{
543    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
544    Xim		 im = (Xim)call_data;
545
546    (void )_XimRegisterTriggerkey(im, (XPointer)&buf_s[2]);
547    return True;
548}
549
550EVENTMASK
551_XimGetWindowEventmask(
552    Xic		 ic)
553{
554    Xim			im = (Xim )ic->core.im;
555    XWindowAttributes	atr;
556
557    if (!XGetWindowAttributes(im->core.display, ic->core.focus_window, &atr))
558	return 0;
559    return (EVENTMASK)atr.your_event_mask;
560}
561
562
563static Bool
564_XimTriggerNotifyCheck(
565    Xim          im,
566    INT16        len,
567    XPointer	 data,
568    XPointer     arg)
569{
570    Xic		 ic  = (Xic)arg;
571    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
572    CARD8	 major_opcode = *((CARD8 *)data);
573    CARD8	 minor_opcode = *((CARD8 *)data + 1);
574    XIMID	 imid = buf_s[0];
575    XICID	 icid = buf_s[1];
576
577    if ((major_opcode == XIM_TRIGGER_NOTIFY_REPLY)
578     && (minor_opcode == 0)
579     && (imid == im->private.proto.imid)
580     && (icid == ic->private.proto.icid))
581	return True;
582    if ((major_opcode == XIM_ERROR)
583     && (minor_opcode == 0)
584     && (buf_s[2] & XIM_IMID_VALID)
585     && (imid == im->private.proto.imid)
586     && (buf_s[2] & XIM_ICID_VALID)
587     && (icid == ic->private.proto.icid))
588	return True;
589    return False;
590}
591
592Bool
593_XimTriggerNotify(
594    Xim		 im,
595    Xic		 ic,
596    int		 mode,
597    CARD32	 idx)
598{
599    CARD32	 buf32[BUFSIZE/4];
600    CARD8	*buf = (CARD8 *)buf32;
601    CARD16	*buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
602    CARD32	*buf_l = (CARD32 *)&buf[XIM_HEADER_SIZE];
603    CARD32	 reply32[BUFSIZE/4];
604    char	*reply = (char *)reply32;
605    XPointer	 preply;
606    int		 buf_size;
607    int		 ret_code;
608    INT16	 len;
609    EVENTMASK	 mask = _XimGetWindowEventmask(ic);
610
611    buf_s[0] = im->private.proto.imid;	/* imid */
612    buf_s[1] = ic->private.proto.icid;	/* icid */
613    buf_l[1] = mode;			/* flag */
614    buf_l[2] = idx;			/* index of keys list */
615    buf_l[3] = mask;			/* select-event-mask */
616
617    len = sizeof(CARD16)		/* sizeof imid */
618	+ sizeof(CARD16)		/* sizeof icid */
619	+ sizeof(CARD32)		/* sizeof flag */
620	+ sizeof(CARD32)		/* sizeof index of key list */
621	+ sizeof(EVENTMASK);		/* sizeof select-event-mask */
622
623    _XimSetHeader((XPointer)buf, XIM_TRIGGER_NOTIFY, 0, &len);
624    if (!(_XimWrite(im, len, (XPointer)buf)))
625	return False;
626    _XimFlush(im);
627    buf_size = BUFSIZE;
628    ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
629				_XimTriggerNotifyCheck, (XPointer)ic);
630    if(ret_code == XIM_TRUE) {
631	preply = reply;
632    } else if(ret_code == XIM_OVERFLOW) {
633	if(len <= 0) {
634	    preply = reply;
635	} else {
636	    buf_size = len;
637	    preply = Xmalloc(len);
638	    ret_code = _XimRead(im, &len, preply, buf_size,
639				_XimTriggerNotifyCheck, (XPointer)ic);
640	    if(ret_code != XIM_TRUE) {
641		Xfree(preply);
642		return False;
643	    }
644	}
645    } else {
646	return False;
647    }
648    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
649    if (*((CARD8 *)preply) == XIM_ERROR) {
650	_XimProcError(im, 0, (XPointer)&buf_s[3]);
651	if(reply != preply)
652	    Xfree(preply);
653	return False;
654    }
655    if(reply != preply)
656	Xfree(preply);
657    return True;
658}
659
660static Bool
661_XimRegCommitInfo(
662    Xic			 ic,
663    char		*string,
664    int			 string_len,
665    KeySym		*keysym,
666    int			 keysym_len)
667{
668    XimCommitInfo	info;
669
670    if (!(info = Xmalloc(sizeof(XimCommitInfoRec))))
671	return False;
672    info->string	= string;
673    info->string_len	= string_len;
674    info->keysym	= keysym;
675    info->keysym_len	= keysym_len;
676    info->next = ic->private.proto.commit_info;
677    ic->private.proto.commit_info = info;
678    return True;
679}
680
681static void
682_XimUnregRealCommitInfo(
683    Xic			ic,
684    Bool		reverse)
685{
686    XimCommitInfo	info;
687    XimCommitInfo	prev_info = NULL;
688
689    info = ic->private.proto.commit_info;
690    while (reverse && info) {
691	if (!info->next)
692	    break;
693	prev_info = info;
694	info = info->next;
695    }
696    if (!info)
697	return;
698
699    Xfree(info->string);
700    Xfree(info->keysym);
701    if (prev_info)
702	prev_info->next = info->next;
703    else
704	ic->private.proto.commit_info = info->next;
705    Xfree(info);
706    return;
707}
708
709static void
710_XimUnregCommitInfo(
711    Xic			ic)
712{
713    _XimUnregRealCommitInfo(ic, False);
714}
715
716static void
717_XimUnregFirstCommitInfo(
718    Xic			ic)
719{
720    _XimUnregRealCommitInfo(ic, True);
721}
722
723void
724_XimFreeCommitInfo(
725    Xic			ic)
726{
727    while (ic->private.proto.commit_info)
728	_XimUnregCommitInfo(ic);
729    return;
730}
731
732static XimCommitInfo
733_XimFirstCommitInfo(
734    Xic			ic)
735{
736    XimCommitInfo info = ic->private.proto.commit_info;
737    while (info) {
738	if (!info->next)
739	    break;
740	info = info->next;
741    }
742    return info;
743}
744
745static Bool
746_XimProcKeySym(
747    Xic			  ic,
748    CARD32		  sym,
749    KeySym		**xim_keysym,
750    int			 *xim_keysym_len)
751{
752    Xim			 im = (Xim)ic->core.im;
753
754    if (!(*xim_keysym = Xmalloc(sizeof(KeySym)))) {
755	_XimError(im, ic, XIM_BadAlloc, (INT16)0, (CARD16)0, (char *)NULL);
756	return False;
757    }
758
759    **xim_keysym = (KeySym)sym;
760    *xim_keysym_len = 1;
761
762    return True;
763}
764
765static Bool
766_XimProcCommit(
767    Xic		  ic,
768    BYTE	 *buf,
769    int		  len,
770    char	**xim_string,
771    int		 *xim_string_len)
772{
773    Xim		 im = (Xim)ic->core.im;
774    char	*string;
775
776    if (!(string = Xmalloc(len + 1))) {
777	_XimError(im, ic, XIM_BadAlloc, (INT16)0, (CARD16)0, (char *)NULL);
778	return False;
779    }
780
781    (void)memcpy(string, (char *)buf, len);
782    string[len] = '\0';
783
784    *xim_string = string;
785    *xim_string_len = len;
786    return True;
787}
788
789static Bool
790_XimCommitRecv(
791    Xim		 im,
792    Xic		 ic,
793    XPointer	 buf)
794{
795    CARD16	*buf_s = (CARD16 *)buf;
796    BITMASK16	 flag = buf_s[0];
797    XKeyEvent	 ev;
798    char	*string = NULL;
799    int		 string_len = 0;
800    KeySym	*keysym = NULL;
801    int		 keysym_len = 0;
802
803    if ((flag & XimLookupBoth) == XimLookupChars) {
804	if (!(_XimProcCommit(ic, (BYTE *)&buf_s[2],
805			 		(int)buf_s[1], &string, &string_len)))
806	    return False;
807
808    } else if ((flag & XimLookupBoth) == XimLookupKeySym) {
809	if (!(_XimProcKeySym(ic, *(CARD32 *)&buf_s[2], &keysym, &keysym_len)))
810	    return False;
811
812    } else if ((flag & XimLookupBoth) == XimLookupBoth) {
813	if (!(_XimProcKeySym(ic, *(CARD32 *)&buf_s[2], &keysym, &keysym_len)))
814	    return False;
815
816	if (!(_XimProcCommit(ic, (BYTE *)&buf_s[5],
817					(int)buf_s[4], &string, &string_len))) {
818	    Xfree(keysym);
819	    return False;
820	}
821    }
822
823    if (!(_XimRegCommitInfo(ic, string, string_len, keysym, keysym_len))) {
824       Xfree(string);
825	Xfree(keysym);
826	_XimError(im, ic, XIM_BadAlloc, (INT16)0, (CARD16)0, (char *)NULL);
827	return False;
828    }
829
830    (void)_XimRespSyncReply(ic, flag);
831
832    bzero(&ev, sizeof(ev));	/* uninitialized : found when running kterm under valgrind */
833
834    ev.type = KeyPress;
835    ev.send_event = False;
836    ev.display = im->core.display;
837    ev.window = ic->core.focus_window;
838    ev.keycode = 0;
839    ev.state = 0;
840
841    ev.time = 0L;
842    ev.serial = LastKnownRequestProcessed(im->core.display);
843
844    if (ic->private.proto.registed_filter_event
845	& (KEYPRESS_MASK | KEYRELEASE_MASK))
846	    _XimFabricateSerial(im, &ev);
847    /* FIXME :
848       I wish there were COMMENTs (!) about the data passed around.
849    */
850#if 0
851    fprintf(stderr,"%s,%d: putback k press   FIXED ev.time=0 ev.serial=%lu\n", __FILE__, __LINE__, ev.serial);
852#endif
853
854    XPutBackEvent(im->core.display, (XEvent *)&ev);
855
856    return True;
857}
858
859Bool
860_XimCommitCallback(
861    Xim		 xim,
862    INT16	 len,
863    XPointer	 data,
864    XPointer	 call_data)
865{
866    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
867    XIMID        imid = buf_s[0];
868    XICID        icid = buf_s[1];
869    Xim		 im = (Xim)call_data;
870    Xic		 ic;
871
872    if ((imid == im->private.proto.imid)
873     && (ic = _XimICOfXICID(im, icid))) {
874	(void)_XimCommitRecv(im, ic, (XPointer)&buf_s[2]);
875	return True;
876    }
877    return False;
878}
879
880void
881_XimProcError(
882    Xim		 im,
883    Xic		 ic,
884    XPointer	 data)
885{
886    return;
887}
888
889Bool
890_XimErrorCallback(
891    Xim		 xim,
892    INT16	 len,
893    XPointer	 data,
894    XPointer	 call_data)
895{
896    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
897    BITMASK16	 flag = buf_s[2];
898    XIMID        imid;
899    XICID        icid;
900    Xim		 im = (Xim)call_data;
901    Xic		 ic = NULL;
902
903    if (flag & XIM_IMID_VALID) {
904	imid = buf_s[0];
905	if (imid != im->private.proto.imid)
906	    return False;
907    }
908    if (flag & XIM_ICID_VALID) {
909	icid = buf_s[1];
910	if (!(ic = _XimICOfXICID(im, icid)))
911	    return False;
912    }
913    _XimProcError(im, ic, (XPointer)&buf_s[3]);
914
915    return True;
916}
917
918Bool
919_XimError(
920    Xim		 im,
921    Xic		 ic,
922    CARD16	 error_code,
923    INT16	 detail_length,
924    CARD16	 type,
925    char	*detail)
926{
927    CARD32	 buf32[BUFSIZE/4];
928    CARD8	*buf = (CARD8 *)buf32;
929    CARD16	*buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
930    INT16	 len = 0;
931
932    buf_s[0] = im->private.proto.imid;	/* imid */
933    buf_s[2] = XIM_IMID_VALID;		/* flag */
934    if (ic) {
935    	buf_s[1] = ic->private.proto.icid;	/* icid */
936	buf_s[2] |= XIM_ICID_VALID;		/* flag */
937    }
938    buf_s[3] = error_code;			/* Error Code */
939    buf_s[4] = detail_length;			/* length of error detail */
940    buf_s[5] = type;				/* type of error detail */
941
942    if (detail_length && detail) {
943	len = detail_length;
944	memcpy((char *)&buf_s[6], detail, len);
945	XIM_SET_PAD(&buf_s[6], len);
946    }
947
948    len += sizeof(CARD16)		/* sizeof imid */
949	 + sizeof(CARD16)		/* sizeof icid */
950	 + sizeof(BITMASK16)		/* sizeof flag */
951	 + sizeof(CARD16)		/* sizeof error_code */
952	 + sizeof(INT16)		/* sizeof length of detail */
953	 + sizeof(CARD16);		/* sizeof type */
954
955    _XimSetHeader((XPointer)buf, XIM_ERROR, 0, &len);
956    if (!(_XimWrite(im, len, (XPointer)buf)))
957	return False;
958    _XimFlush(im);
959    return True;
960}
961
962static int
963_Ximctsconvert(
964    XlcConv	 conv,
965    char	*from,
966    int		 from_len,
967    char	*to,
968    int		 to_len,
969    Status	*state)
970{
971    int		 from_left;
972    int		 to_left;
973    int		 from_savelen;
974    int		 to_savelen;
975    int		 from_cnvlen;
976    int		 to_cnvlen;
977    char	*from_buf;
978    char	*to_buf;
979    char	 scratchbuf[BUFSIZ];
980    Status	 tmp_state;
981
982    if (!state)
983	state = &tmp_state;
984
985    if (!conv || !from || !from_len) {
986	*state = XLookupNone;
987	return 0;
988    }
989
990    /* Reset the converter.  The CompoundText at 'from' starts in
991       initial state.  */
992    _XlcResetConverter(conv);
993
994    from_left = from_len;
995    to_left = BUFSIZ;
996    from_cnvlen = 0;
997    to_cnvlen = 0;
998    for (;;) {
999	from_buf = &from[from_cnvlen];
1000	from_savelen = from_left;
1001	to_buf = &scratchbuf[to_cnvlen];
1002	to_savelen = to_left;
1003	if (_XlcConvert(conv, (XPointer *)&from_buf, &from_left,
1004				 (XPointer *)&to_buf, &to_left, NULL, 0) < 0) {
1005	    *state = XLookupNone;
1006	    return 0;
1007	}
1008	from_cnvlen += (from_savelen - from_left);
1009	to_cnvlen += (to_savelen - to_left);
1010	if (from_left == 0) {
1011	    if (!to_cnvlen) {
1012		*state = XLookupNone;
1013		return 0;
1014           }
1015	   break;
1016	}
1017    }
1018
1019    if (!to || !to_len || (to_len < to_cnvlen)) {
1020       *state = XBufferOverflow;
1021    } else {
1022       memcpy(to, scratchbuf, to_cnvlen);
1023       *state = XLookupChars;
1024    }
1025    return to_cnvlen;
1026}
1027
1028int
1029_Ximctstombs(XIM xim, char *from, int from_len,
1030	     char *to, int to_len, Status *state)
1031{
1032    return _Ximctsconvert(((Xim)xim)->private.proto.ctom_conv,
1033			  from, from_len, to, to_len, state);
1034}
1035
1036int
1037_Ximctstowcs(
1038    XIM		 xim,
1039    char	*from,
1040    int		 from_len,
1041    wchar_t	*to,
1042    int		 to_len,
1043    Status	*state)
1044{
1045    Xim		 im = (Xim)xim;
1046    XlcConv	 conv = im->private.proto.ctow_conv;
1047    int		 from_left;
1048    int		 to_left;
1049    int		 from_savelen;
1050    int		 to_savelen;
1051    int		 from_cnvlen;
1052    int		 to_cnvlen;
1053    char	*from_buf;
1054    wchar_t	*to_buf;
1055    wchar_t	 scratchbuf[BUFSIZ];
1056    Status	 tmp_state;
1057
1058    if (!state)
1059	state = &tmp_state;
1060
1061    if (!conv || !from || !from_len) {
1062	*state = XLookupNone;
1063	return 0;
1064    }
1065
1066    /* Reset the converter.  The CompoundText at 'from' starts in
1067       initial state.  */
1068    _XlcResetConverter(conv);
1069
1070    from_left = from_len;
1071    to_left = BUFSIZ;
1072    from_cnvlen = 0;
1073    to_cnvlen = 0;
1074    for (;;) {
1075	from_buf = &from[from_cnvlen];
1076       from_savelen = from_left;
1077       to_buf = &scratchbuf[to_cnvlen];
1078       to_savelen = to_left;
1079	if (_XlcConvert(conv, (XPointer *)&from_buf, &from_left,
1080				 (XPointer *)&to_buf, &to_left, NULL, 0) < 0) {
1081	    *state = XLookupNone;
1082	    return 0;
1083	}
1084	from_cnvlen += (from_savelen - from_left);
1085       to_cnvlen += (to_savelen - to_left);
1086	if (from_left == 0) {
1087           if (!to_cnvlen){
1088		*state = XLookupNone;
1089               return 0;
1090           }
1091	    break;
1092	}
1093    }
1094
1095    if (!to || !to_len || (to_len < to_cnvlen)) {
1096       *state = XBufferOverflow;
1097    } else {
1098       memcpy(to, scratchbuf, to_cnvlen * sizeof(wchar_t));
1099       *state = XLookupChars;
1100    }
1101    return to_cnvlen;
1102}
1103
1104int
1105_Ximctstoutf8(
1106    XIM		 xim,
1107    char	*from,
1108    int		 from_len,
1109    char	*to,
1110    int		 to_len,
1111    Status	*state)
1112{
1113    return _Ximctsconvert(((Xim)xim)->private.proto.ctoutf8_conv,
1114			  from, from_len, to, to_len, state);
1115}
1116
1117int
1118_XimProtoMbLookupString(
1119    XIC			 xic,
1120    XKeyEvent		*ev,
1121    char		*buffer,
1122    int			 bytes,
1123    KeySym		*keysym,
1124    Status		*state)
1125{
1126    Xic			 ic = (Xic)xic;
1127    Xim			 im = (Xim)ic->core.im;
1128    int			 ret;
1129    Status		 tmp_state;
1130    XimCommitInfo	 info;
1131
1132    if (!IS_SERVER_CONNECTED(im))
1133	return 0;
1134
1135    if (!state)
1136	state = &tmp_state;
1137
1138    if ((ev->type == KeyPress) && (ev->keycode == 0)) { /* Filter function */
1139	if (!(info = _XimFirstCommitInfo(ic))) {
1140	    *state = XLookupNone;
1141	    return 0;
1142	}
1143
1144	ret = im->methods->ctstombs((XIM)im, info->string,
1145			 	info->string_len, buffer, bytes, state);
1146	if (*state == XBufferOverflow)
1147            return ret;
1148	if (keysym && (info->keysym && *(info->keysym))) {
1149	    *keysym = *(info->keysym);
1150	    if (*state == XLookupChars)
1151		*state = XLookupBoth;
1152	    else
1153		*state = XLookupKeySym;
1154	}
1155	_XimUnregFirstCommitInfo(ic);
1156
1157    } else  if (ev->type == KeyPress) {
1158	ret = _XimLookupMBText(ic, ev, buffer, bytes, keysym, NULL);
1159	if (ret > 0) {
1160           if (ret > bytes)
1161               *state = XBufferOverflow;
1162           else if (keysym && *keysym != NoSymbol)
1163		*state = XLookupBoth;
1164	    else
1165		*state = XLookupChars;
1166	} else {
1167	    if (keysym && *keysym != NoSymbol)
1168		*state = XLookupKeySym;
1169	    else
1170		*state = XLookupNone;
1171	}
1172    } else {
1173	*state = XLookupNone;
1174	ret = 0;
1175    }
1176
1177    return ret;
1178}
1179
1180int
1181_XimProtoWcLookupString(
1182    XIC			 xic,
1183    XKeyEvent		*ev,
1184    wchar_t		*buffer,
1185    int			 bytes,
1186    KeySym		*keysym,
1187    Status		*state)
1188{
1189    Xic			 ic = (Xic)xic;
1190    Xim			 im = (Xim)ic->core.im;
1191    int			 ret;
1192    Status		 tmp_state;
1193    XimCommitInfo	 info;
1194
1195    if (!IS_SERVER_CONNECTED(im))
1196	return 0;
1197
1198    if (!state)
1199	state = &tmp_state;
1200
1201    if (ev->type == KeyPress && ev->keycode == 0) { /* Filter function */
1202	if (!(info = _XimFirstCommitInfo(ic))) {
1203           *state = XLookupNone;
1204	    return 0;
1205	}
1206
1207	ret = im->methods->ctstowcs((XIM)im, info->string,
1208			 	info->string_len, buffer, bytes, state);
1209	if (*state == XBufferOverflow)
1210           return ret;
1211	if (keysym && (info->keysym && *(info->keysym))) {
1212	    *keysym = *(info->keysym);
1213	    if (*state == XLookupChars)
1214		*state = XLookupBoth;
1215	    else
1216		*state = XLookupKeySym;
1217	}
1218	_XimUnregFirstCommitInfo(ic);
1219
1220    } else if (ev->type == KeyPress) {
1221	ret = _XimLookupWCText(ic, ev, buffer, bytes, keysym, NULL);
1222	if (ret > 0) {
1223           if (ret > bytes)
1224               *state = XBufferOverflow;
1225           else if (keysym && *keysym != NoSymbol)
1226		*state = XLookupBoth;
1227	    else
1228		*state = XLookupChars;
1229	} else {
1230	    if (keysym && *keysym != NoSymbol)
1231		*state = XLookupKeySym;
1232	    else
1233		*state = XLookupNone;
1234	}
1235    } else {
1236	*state = XLookupNone;
1237	ret = 0;
1238    }
1239
1240    return ret;
1241}
1242
1243int
1244_XimProtoUtf8LookupString(
1245    XIC			 xic,
1246    XKeyEvent		*ev,
1247    char		*buffer,
1248    int			 bytes,
1249    KeySym		*keysym,
1250    Status		*state)
1251{
1252    Xic			 ic = (Xic)xic;
1253    Xim			 im = (Xim)ic->core.im;
1254    int			 ret;
1255    Status		 tmp_state;
1256    XimCommitInfo	 info;
1257
1258    if (!IS_SERVER_CONNECTED(im))
1259	return 0;
1260
1261    if (!state)
1262	state = &tmp_state;
1263
1264    if (ev->type == KeyPress && ev->keycode == 0) { /* Filter function */
1265	if (!(info = _XimFirstCommitInfo(ic))) {
1266           *state = XLookupNone;
1267	    return 0;
1268	}
1269
1270	ret = im->methods->ctstoutf8((XIM)im, info->string,
1271			 	info->string_len, buffer, bytes, state);
1272	if (*state == XBufferOverflow)
1273           return ret;
1274	if (keysym && (info->keysym && *(info->keysym))) {
1275	    *keysym = *(info->keysym);
1276	    if (*state == XLookupChars)
1277		*state = XLookupBoth;
1278	    else
1279		*state = XLookupKeySym;
1280	}
1281	_XimUnregFirstCommitInfo(ic);
1282
1283    } else if (ev->type == KeyPress) {
1284	ret = _XimLookupUTF8Text(ic, ev, buffer, bytes, keysym, NULL);
1285	if (ret > 0) {
1286           if (ret > bytes)
1287               *state = XBufferOverflow;
1288           else if (keysym && *keysym != NoSymbol)
1289		*state = XLookupBoth;
1290	    else
1291		*state = XLookupChars;
1292	} else {
1293	    if (keysym && *keysym != NoSymbol)
1294		*state = XLookupKeySym;
1295	    else
1296		*state = XLookupNone;
1297	}
1298    } else {
1299	*state = XLookupNone;
1300	ret = 0;
1301    }
1302
1303    return ret;
1304}
1305