1/***********************************************************************
2Copyright 1993 by Digital Equipment Corporation, Maynard, Massachusetts,
3Copyright 1994 by FUJITSU LIMITED
4Copyright 1994 by Sony Corporation
5
6                        All Rights Reserved
7
8Permission to use, copy, modify, and distribute this software and its
9documentation for any purpose and without fee is hereby granted,
10provided that the above copyright notice appear in all copies and that
11both that copyright notice and this permission notice appear in
12supporting documentation, and that the names of Digital, FUJITSU
13LIMITED and Sony Corporation not be used in advertising or publicity
14pertaining to distribution of the software without specific, written
15prior permission.
16
17DIGITAL, FUJITSU LIMITED AND SONY CORPORATION DISCLAIMS ALL WARRANTIES
18WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
19MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL, FUJITSU LIMITED
20AND SONY CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
21CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
22USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
23OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
24PERFORMANCE OF THIS SOFTWARE.
25
26  Author: Hiroyuki Miyamoto  Digital Equipment Corporation
27                             miyamoto@jrd.dec.com
28  Modifier: Takashi Fujiwara FUJITSU LIMITED
29			     fujiwara@a80.tech.yk.fujitsu.co.jp
30	    Makoto Wakamatsu Sony Corporation
31		 	     makoto@sm.sony.co.jp
32
33***********************************************************************/
34
35#ifdef HAVE_CONFIG_H
36#include <config.h>
37#endif
38#include "Xlibint.h"
39#include "Xlcint.h"
40#include "Ximint.h"
41#include "XlcPubI.h"
42
43#define sz_CARD8                 1
44#define sz_INT8                  1
45#define sz_CARD16                2
46#define sz_INT16                 2
47#define sz_BITMASK16             sz_CARD16
48#define sz_CARD32                4
49#define sz_INT32                 4
50#define sz_BITMASK32             sz_CARD32
51#define sz_XIMID                 sizeof(XIMID)
52#define sz_XICID                 sizeof(XICID)
53#define sz_XIMATTRID             sizeof(XIMATTRID)
54#define sz_XICATTRID             sizeof(XICATTRID)
55#define sz_ximPacketHeader       (XIM_HEADER_SIZE + sz_XIMID + sz_XICID)
56#define sz_ximGeometry           0
57#define sz_ximStrConversion      (sz_CARD32 + sz_CARD32 + sz_CARD32 + sz_CARD32)
58#define sz_ximPreeditStart       0
59#define sz_ximPreeditStartReply  sz_INT32
60#define sz_ximPreeditCaret       (sz_INT32 + sz_CARD32 + sz_CARD32)
61#define sz_ximPreeditCaretReply  sz_CARD32
62#define sz_ximPreeditDone        0
63#define sz_ximStatusStart        0
64#define sz_ximStatusDone         0
65
66typedef enum {
67    XimCbSuccess,
68    XimCbNoCallback,
69    XimCbError,
70    XimCbQueued,
71    XimCbBadContextID,
72    XimCbBadOpcode
73} XimCbStatus;
74
75typedef XimCbStatus (*XimCb)(
76			     Xim, Xic, char*, int
77			     );
78
79#define PACKET_TO_MAJOROPCODE(p) (*(CARD8*)((CARD8*)(p)))
80#define PACKET_TO_MINOROPCODE(p) (*(CARD8*)((CARD8*)(p) + sz_CARD8))
81#define PACKET_TO_LENGTH(p) (*(CARD16*)((CARD8*)(p) + sz_CARD8 + sz_CARD8))
82#define PACKET_TO_IMID(p) (*(XIMID*)((CARD8*)(p) + XIM_HEADER_SIZE))
83#define PACKET_TO_ICID(p) (*(XICID*)((CARD8*)(p) + XIM_HEADER_SIZE + sz_XIMID))
84
85#define _XimWriteData(im,len,data) \
86    (im->private.proto.write((im),(len),(XPointer)(data)))
87#define _XimReadData(im,buf,buf_len,len) \
88    (im->private.proto.read((im),(XPointer)(buf),(buf_len),&(len)))
89#define _XimFlushData(im) im->private.proto.flush((im))
90
91static XimCbStatus _XimGeometryCallback(Xim, Xic, char*, int);
92static XimCbStatus _XimStrConversionCallback(Xim, Xic, char*, int);
93static XimCbStatus _XimPreeditStartCallback(Xim, Xic, char*, int);
94static XimCbStatus _XimPreeditDoneCallback(Xim, Xic, char*, int);
95static void _free_memory_for_text(XIMText*);
96static XimCbStatus _XimPreeditDrawCallback(Xim, Xic, char*, int);
97static XimCbStatus _XimPreeditCaretCallback(Xim, Xic, char*, int);
98static XimCbStatus _XimStatusStartCallback(Xim, Xic, char*, int);
99static XimCbStatus _XimStatusDoneCallback(Xim, Xic, char*, int);
100static XimCbStatus _XimStatusDrawCallback(Xim, Xic, char*, int);
101static XimCbStatus _XimPreeditStateNotifyCallback(Xim, Xic, char *, int);
102
103#if defined(__STDC__) && ((defined(sun) && defined(SVR4)) || defined(WIN32))
104#define RConst /**/
105#else
106#define RConst const
107#endif
108
109/* NOTE:
110 * the table below depends on the protocol number
111 * defined in the IM Protocol document.
112 */
113static RConst XimCb callback_table[] = {
114    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* #000-009 */
115    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* #010-019 */
116    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* #020-029 */
117    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* #030-039 */
118    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* #040-049 */
119    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* #050-059 */
120    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* #060-069 */
121    _XimGeometryCallback,	/* #070 */
122    _XimStrConversionCallback,	/* #071 */
123    NULL,			/* #072 */
124    _XimPreeditStartCallback,	/* #073 */
125    NULL,			/* #074 */
126    _XimPreeditDrawCallback,	/* #075 */
127    _XimPreeditCaretCallback,	/* #076 */
128    NULL,			/* #077 */
129    _XimPreeditDoneCallback,	/* #078 */
130    _XimStatusStartCallback,	/* #079 */
131    _XimStatusDrawCallback,	/* #080 */
132    _XimStatusDoneCallback,	/* #081 */
133    _XimPreeditStateNotifyCallback	/* #082 */
134    };
135
136
137static Bool
138_XimIsReadyForProcess(Xic ic)
139{
140    return(!ic->private.proto.waitCallback); /* check HM */
141}
142
143static void
144_XimProcessPendingCallbacks(Xic ic)
145{
146    XimPendingCallback pcbq;
147
148    while (((pcbq = ic->private.proto.pend_cb_que) != (XimPendingCallback)NULL)
149	   && _XimIsReadyForProcess(ic)) {
150	(void) (*callback_table[pcbq->major_opcode])(pcbq->im,
151						     pcbq->ic,
152						     pcbq->proto,
153						     pcbq->proto_len);
154	ic->private.proto.pend_cb_que = pcbq->next;
155	Xfree(pcbq->proto);	/* free memory of XimPendingCallback */
156	Xfree(pcbq);
157    }
158}
159
160static void
161_XimPutCbIntoQueue(Xic ic, XimPendingCallback call_data)
162{
163    XimPendingCallback pcbq = ic->private.proto.pend_cb_que;
164
165    /* Queuing is FIFO
166     */
167    while (pcbq != (XimPendingCallback)NULL) {
168	if (pcbq->next == (XimPendingCallback)NULL) {
169	    break;
170	}
171	pcbq = pcbq->next;
172    }
173    if (pcbq == (XimPendingCallback)NULL) {
174	ic->private.proto.pend_cb_que = call_data;
175    }
176    else {
177	pcbq->next = call_data;
178    }
179}
180
181Bool
182_XimCbDispatch(Xim xim,
183	       INT16 len,
184	       XPointer data,
185	       XPointer call_data)
186{
187    /* `data' points to the beginning of the packet defined in IM Protocol doc.
188     */
189    int major_opcode = PACKET_TO_MAJOROPCODE(data);
190    XIMID imid = PACKET_TO_IMID(data);
191    XICID icid = PACKET_TO_ICID(data);
192    Xim im = (Xim)call_data;	/* check HM */
193    Xic ic = _XimICOfXICID(im, icid);
194    char* proto;
195    int proto_len;
196
197    /* check validity of im/ic
198     */
199    if ((imid != im->private.proto.imid) || !ic) {
200	return False; /* status = XimCbBadContextID; */
201    }
202
203    /* process pending callbacks
204     */
205    _XimProcessPendingCallbacks(ic);
206
207    /* check if the protocol should be processed here
208     */
209    if (major_opcode > 82) {
210	return False; /* status = XimCbBadOpcode; */
211    }
212    if (!callback_table[major_opcode]) {
213	return False; /* status = XimCbBadOpcode; */
214    }
215
216    /* move the pointer ahead by the IM Protocol packet header size
217     */
218    proto = (char*)data + sz_ximPacketHeader;
219    proto_len = (int)len - sz_ximPacketHeader;
220
221    /* check if it can be processed right away
222     * and if no, queue the protocol, otherwise invoke a callback
223     */
224    if (!_XimIsReadyForProcess(ic)) {
225
226	/* queue the protocol
227	 */
228	XimPendingCallback pcb;
229	char *proto_buf = (proto_len > 0) ? Xmalloc(proto_len) : NULL;
230
231	pcb = Xmalloc(sizeof(XimPendingCallbackRec));
232	if (pcb && (proto_len <= 0 || proto_buf)) {
233	    if (proto_len > 0)
234		memcpy(proto_buf, proto, proto_len);
235
236	    pcb->major_opcode = major_opcode;
237	    pcb->im = im;
238	    pcb->ic = ic;
239	    pcb->proto = proto_buf;
240	    pcb->proto_len = proto_len;
241	    pcb->next = (XimPendingCallback)NULL; /* queue is FIFO */
242	    _XimPutCbIntoQueue(ic, pcb);
243	    /* status = XimCbQueued; */
244	} else {
245	    /* status = XimCbError; */
246	    Xfree(pcb);
247	    Xfree(proto_buf);
248	}
249    }
250    else {
251	/* invoke each callback according to the major opcode.
252	 * `proto' points to the next address of IM-ID and IC-ID.
253	 * `proto_len' specifies the packet length.
254	 */
255	(void) (*callback_table[major_opcode])(im, ic, proto, proto_len);
256    }
257    return True;
258}
259
260static XimCbStatus
261_XimGeometryCallback(Xim im,
262		     Xic ic,
263		     char* proto,
264		     int len)
265{
266    XICCallback* cb = &ic->core.geometry_callback;
267
268    /* invoke the callback
269     */
270    if (cb && cb->callback) {
271	(*cb->callback)((XIC)ic, cb->client_data, (XPointer)NULL);
272    }
273    else {
274
275	/* no callback registered
276	 */
277	return XimCbNoCallback;
278    }
279
280    return XimCbSuccess;
281}
282
283static XimCbStatus
284_XimStrConversionCallback(Xim im,
285			  Xic ic,
286			  char* proto,
287			  int len)
288{
289    XICCallback* cb = &ic->core.string_conversion_callback; /* check HM */
290    XIMStringConversionCallbackStruct cbrec;
291
292    /* invoke the callback
293     */
294    if (cb && cb->callback) {
295	int p = XIM_HEADER_SIZE;
296	cbrec.position = (XIMStringConversionPosition)
297	    *(CARD32*)&proto[p]; p += sz_CARD32;
298	cbrec.direction = (XIMCaretDirection)
299	    *(CARD32*)&proto[p]; p += sz_CARD32;
300	cbrec.operation = (XIMStringConversionOperation)
301	    *(CARD32*)&proto[p]; p += sz_CARD32;
302	cbrec.factor = (unsigned short)
303	    *(CARD32*)&proto[p];
304
305	(*cb->callback)((XIC)ic, cb->client_data, (XPointer)&cbrec);
306    }
307    else {
308
309	/* no callback registered
310	 */
311	_XimError(im, ic,
312		  (CARD16)XIM_BadSomething,
313		  (INT16)len,
314		  (CARD16)XIM_STR_CONVERSION,
315		  (char*)proto); /* send XIM_ERROR */
316	return XimCbNoCallback;
317    }
318
319    /* send a reply
320     */
321    {
322	CARD8	*buf;
323	INT16	 buf_len;
324	int	 p, length_in_bytes, i;
325
326	/* Assumption:
327	 * `cbrec.text->length' means the string length in characters
328	 */
329	{
330	    size_t blen;
331	    length_in_bytes = (cbrec.text->encoding_is_wchar)?
332		sizeof(wchar_t) * cbrec.text->length: /* wchar */
333		strlen(cbrec.text->string.mbs);	/* mb */
334	    blen = XIM_HEADER_SIZE +
335		sz_CARD16 +
336		2 + length_in_bytes +
337		XIM_PAD(2 + length_in_bytes) +
338		2 + 2 + sz_CARD32 * cbrec.text->length;
339	    buf = Xmalloc(blen);
340	    buf_len = (INT16) blen;
341	}
342	_XimSetHeader((XPointer)buf, XIM_STR_CONVERSION_REPLY, 0, &buf_len);
343	buf_len -= XIM_HEADER_SIZE; /* added by _XimSetHeader (HACK) */
344	p = XIM_HEADER_SIZE;
345	*(CARD16*)&buf[p] = (CARD16)im->private.proto.imid; p += sz_CARD16;
346	*(CARD16*)&buf[p] = (CARD16)ic->private.proto.icid; p += sz_CARD16;
347	*(CARD16*)&buf[p] = (CARD16)cbrec.text->length; p += sz_CARD16;
348	memcpy(&buf[p],&cbrec.text->string.mbs,length_in_bytes);
349	p += length_in_bytes;
350	*(CARD16*)&buf[p] = (CARD16)(sz_CARD32*cbrec.text->length);
351	p += XIM_PAD(2);
352	for (i = 0; i < (int)cbrec.text->length; i++) {
353	    *(CARD32*)&buf[p] = (CARD32)cbrec.text->feedback[i];
354	    p += sz_CARD32;
355	}
356
357	if (!(_XimWriteData(im, buf_len, buf))) {
358	    return XimCbError;
359	}
360	_XimFlushData(im);
361
362	Xfree(buf);
363    }
364
365    return XimCbSuccess;
366}
367
368static XimCbStatus
369_XimPreeditStartCallback(Xim im,
370			 Xic ic,
371			 char* proto,
372			 int len)
373{
374    XICCallback* cb = &ic->core.preedit_attr.start_callback;
375    int ret;
376
377    /* invoke the callback
378     */
379    if (cb && cb->callback){
380	ret = (*(cb->callback))((XIC)ic, cb->client_data, (XPointer)NULL);
381    }
382    else {
383
384	/* no callback registered
385	 */
386	_XimError(im, ic,
387		  (CARD16)XIM_BadSomething,
388		  (INT16)len,
389		  (CARD16)XIM_PREEDIT_START,
390		  (char*)proto); /* send XIM_ERROR */
391	return XimCbNoCallback;
392    }
393
394    /* send a reply
395     */
396    {
397	CARD32 buf32[(sz_ximPacketHeader + sz_ximPreeditStartReply) / 4];
398	CARD8 *buf = (CARD8 *)buf32;
399	INT16 buf_len = sz_XIMID + sz_XICID + sz_ximPreeditStartReply;
400	int p;
401
402	_XimSetHeader((XPointer)buf, XIM_PREEDIT_START_REPLY, 0, &buf_len);
403	p = XIM_HEADER_SIZE;
404	*(CARD16*)&buf[p] = (CARD16)im->private.proto.imid; p += sz_CARD16;
405	*(CARD16*)&buf[p] = (CARD16)ic->private.proto.icid; p += sz_CARD16;
406	*(INT32*)&buf[p]  = (INT32)ret;
407
408	if (!(_XimWriteData(im, buf_len, buf))) {
409	    return XimCbError;
410	}
411	_XimFlushData(im);
412    }
413
414    return XimCbSuccess;
415}
416
417static XimCbStatus
418_XimPreeditDoneCallback(Xim im,
419			Xic ic,
420			char* proto,
421			int len)
422{
423    XICCallback* cb = &ic->core.preedit_attr.done_callback;
424
425    /* invoke the callback
426     */
427    if (cb && cb->callback) {
428	(*cb->callback)((XIC)ic, cb->client_data, (XPointer)NULL);
429    }
430    else {
431
432	/* no callback registered
433	 */
434	return XimCbNoCallback;
435    }
436
437    return XimCbSuccess;
438}
439
440static void
441_read_text_from_packet(Xim im,
442		       char* buf,
443		       XIMText** text_ptr)
444{
445    int status;
446    XIMText* text;
447    int tmp_len;
448    char* tmp_buf;
449    Status s = 0;
450
451    status = (int)*(BITMASK32*)buf; buf += sz_BITMASK32;
452
453    /* string part
454     */
455    if (status & 0x00000001) /* "no string" bit on */ {
456	buf += sz_CARD16;	/* skip "length of preedit string" */
457	buf += 2;		/* pad */
458	*text_ptr = (XIMText*)NULL;
459	return;
460    }
461
462    *text_ptr = text = Xmalloc(sizeof(XIMText));
463    if (text == (XIMText*)NULL) return;
464
465	tmp_len = (int)*(CARD16*)buf;
466	buf += sz_CARD16;
467	if ((tmp_buf = Xmalloc(tmp_len + 1))) {
468	    memcpy(tmp_buf, buf, tmp_len);
469	    tmp_buf[tmp_len] = '\0';
470
471	    text->encoding_is_wchar = False;
472	    text->length = im->methods->ctstombs((XIM)im,
473					tmp_buf, tmp_len,
474					NULL, 0, &s); /* CT? HM */
475	    if (s != XLookupNone) {
476#ifndef NO_DEC_I18N_FIX
477                /* Allow for NULL-terminated */
478                if ((text->string.multi_byte = Xmalloc(text->length *
479                      XLC_PUBLIC(im->core.lcd,mb_cur_max) + 1))) {
480#else
481		if (text->string.multi_byte = Xmalloc(text->length+1)) {
482#endif
483			int tmp;
484#ifndef NO_DEC_I18N_FIX
485                        char *char_tmp;
486                        int char_len;
487#endif
488			tmp = im->methods->ctstombs((XIM)im,
489					   tmp_buf, tmp_len,
490#ifndef NO_DEC_I18N_FIX
491                                           text->string.multi_byte,
492                                           text->length * XLC_PUBLIC(im->core.lcd,mb_cur_max) + 1,
493#else
494					   text->string.multi_byte, text->length,
495#endif
496					   &s);
497			text->string.multi_byte[tmp] = '\0';
498#ifndef NO_DEC_I18N_FIX
499                        text->length = 0;
500                        char_tmp =  text->string.multi_byte;
501                        while (*char_tmp != '\0') {
502                              char_len = mblen(char_tmp, strlen(char_tmp));
503                              char_tmp = char_tmp + char_len;
504                              (text->length)++;
505                        }
506#endif
507		}
508	    }
509	    else {
510		text->length = 0;
511		text->string.multi_byte = NULL;
512	    }
513
514	    Xfree(tmp_buf);
515	}
516	buf += tmp_len;
517
518	buf += XIM_PAD(sz_CARD16 + tmp_len); /* pad */
519
520    /* feedback part
521     */
522    if (status & 0x00000002) /* "no feedback" bit on */ {
523	text->feedback = (XIMFeedback*)NULL;
524    }
525    else {
526	int i, j;
527
528	i = (int)*(CARD16*)buf; buf += sz_CARD16;
529	buf += sz_CARD16; /* skip `unused' */
530	text->feedback = Xmalloc(i*(sizeof(XIMFeedback)/sizeof(CARD32)));
531	j = 0;
532	while (i > 0) {
533	    text->feedback[j] = (XIMFeedback)*(CARD32*)buf;
534	    buf += sz_CARD32;
535	    i -= sz_CARD32;
536	    j++;
537	}
538	/*
539	 * text->length tells how long both the status string and
540	 * the feedback array are. If there's "no string" the
541	 * text->length was set to zero previously. See above.
542	 * But if there is feedback (i.e. not "no feedback") then
543	 * we need to convey the length of the feedback array.
544	 * It might have been better if the protocol sent two
545	 * different values, one for the length of the status
546	 * string and one for the length of the feedback array.
547	 */
548	if (status & 0x00000001) /* "no string" bit on */ {
549	    text->length = j;
550	}
551    }
552}
553
554static void
555_free_memory_for_text(XIMText* text)
556{
557    if (text) {
558        Xfree(text->string.multi_byte);
559        Xfree(text->feedback);
560	Xfree(text);
561    }
562}
563
564static XimCbStatus
565_XimPreeditDrawCallback(Xim im,
566			Xic ic,
567			char* proto,
568			int len)
569{
570    XICCallback* cb = &ic->core.preedit_attr.draw_callback;
571    XIMPreeditDrawCallbackStruct cbs;
572
573    /* invoke the callback
574     */
575    if (cb && cb->callback) {
576	cbs.caret      = (int)*(INT32*)proto; proto += sz_INT32;
577	cbs.chg_first  = (int)*(INT32*)proto; proto += sz_INT32;
578	cbs.chg_length = (int)*(INT32*)proto; proto += sz_INT32;
579	_read_text_from_packet(im, proto, &cbs.text);
580
581	(*cb->callback)((XIC)ic, cb->client_data, (XPointer)&cbs);
582
583	_free_memory_for_text((XIMText*)cbs.text);
584    }
585    else {
586
587	/* no callback registered
588	 */
589	return XimCbNoCallback;
590    }
591
592    return XimCbSuccess;
593}
594
595static XimCbStatus
596_XimPreeditCaretCallback(Xim im,
597			 Xic ic,
598			 char* proto,
599			 int len)
600{
601    XICCallback* cb = &ic->core.preedit_attr.caret_callback;
602    XIMPreeditCaretCallbackStruct cbs;
603
604    /* invoke the callback
605     */
606    if (cb && cb->callback) {
607	cbs.position  = (int)*(INT32*)proto; proto += sz_INT32;
608	cbs.direction = (XIMCaretDirection)*(CARD32*)proto; proto += sz_CARD32;
609	cbs.style     = (XIMCaretStyle)*(CARD32*)proto; proto += sz_CARD32;
610
611	(*cb->callback)((XIC)ic, cb->client_data, (XPointer)&cbs);
612    }
613    else {
614
615	/* no callback registered
616	 */
617	_XimError(im, ic,
618		  (CARD16)XIM_BadSomething,
619		  (INT16)len,
620		  (CARD16)XIM_PREEDIT_CARET,
621		  (char*)proto); /* send XIM_ERROR */
622	return XimCbNoCallback;
623    }
624
625    /* Send a reply
626     */
627    {
628	CARD8 buf[sz_ximPacketHeader + sz_ximPreeditCaretReply];
629	INT16 rlen = sz_XIMID + sz_XICID + sz_ximPreeditCaretReply;
630	int p;
631
632	_XimSetHeader((XPointer)buf, XIM_PREEDIT_CARET_REPLY, 0, &rlen);
633	p = XIM_HEADER_SIZE;
634	*(CARD16*)&buf[p] = (CARD16)im->private.proto.imid; p += sz_CARD16;
635	*(CARD16*)&buf[p] = (CARD16)ic->private.proto.icid; p += sz_CARD16;
636	*(CARD32*)&buf[p] = (CARD32)cbs.position;
637
638	if (!(_XimWriteData(im, rlen, buf))) {
639	    return XimCbError;
640	}
641	_XimFlushData(im);
642    }
643
644    return XimCbSuccess;
645}
646
647static XimCbStatus
648_XimStatusStartCallback(Xim im,
649			Xic ic,
650			char* proto,
651			int len)
652{
653    XICCallback* cb = &ic->core.status_attr.start_callback;
654
655    /* invoke the callback
656     */
657    if (cb && cb->callback) {
658	(*cb->callback)((XIC)ic, cb->client_data, (XPointer)NULL);
659    }
660    else {
661
662	/* no callback registered
663	 */
664	return XimCbNoCallback;
665    }
666
667    return XimCbSuccess;
668}
669
670static XimCbStatus
671_XimStatusDoneCallback(Xim im,
672		       Xic ic,
673		       char* proto,
674		       int len)
675{
676    XICCallback* cb = &ic->core.status_attr.done_callback;
677
678    /* invoke the callback
679     */
680    if (cb && cb->callback) {
681	(*cb->callback)((XIC)ic, cb->client_data, (XPointer)NULL);
682    }
683    else {
684
685	/* no callback registered
686	 */
687	return XimCbNoCallback;
688    }
689
690    return XimCbSuccess;
691}
692
693static XimCbStatus
694_XimStatusDrawCallback(Xim im,
695		       Xic ic,
696		       char* proto,
697		       int len)
698{
699    XICCallback* cb = &ic->core.status_attr.draw_callback;
700    XIMStatusDrawCallbackStruct cbs;
701
702    /* invoke the callback
703     */
704    if (cb && cb->callback) {
705	cbs.type = (XIMStatusDataType)*(CARD32*)proto; proto += sz_CARD32;
706	if (cbs.type == XIMTextType) {
707	    _read_text_from_packet(im, proto, &cbs.data.text);
708	}
709	else if (cbs.type == XIMBitmapType) {
710	    cbs.data.bitmap = (Pixmap)*(CARD32*)proto;
711	}
712
713	(*cb->callback)((XIC)ic, cb->client_data, (XPointer)&cbs);
714
715	if (cbs.type == XIMTextType)
716	    _free_memory_for_text((XIMText *)cbs.data.text);
717    }
718    else {
719
720	/* no callback registered
721	 */
722	return XimCbNoCallback;
723    }
724
725    return XimCbSuccess;
726}
727
728static XimCbStatus
729_XimPreeditStateNotifyCallback( Xim im, Xic ic, char* proto, int len )
730{
731    XICCallback	*cb = &ic->core.preedit_attr.state_notify_callback;
732
733    /* invoke the callback
734     */
735    if( cb  &&  cb->callback ) {
736	XIMPreeditStateNotifyCallbackStruct cbrec;
737
738	cbrec.state = *(BITMASK32 *)proto;
739	(*cb->callback)( (XIC)ic, cb->client_data, (XPointer)&cbrec );
740    }
741    else {
742	/* no callback registered
743	 */
744	return XimCbNoCallback;
745    }
746
747    return XimCbSuccess;
748}
749
750