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