Home | History | Annotate | Line # | Download | only in ximcp
      1 /***********************************************************************
      2 Copyright 1993 by Digital Equipment Corporation, Maynard, Massachusetts,
      3 Copyright 1994 by FUJITSU LIMITED
      4 Copyright 1994 by Sony Corporation
      5 
      6                         All Rights Reserved
      7 
      8 Permission to use, copy, modify, and distribute this software and its
      9 documentation for any purpose and without fee is hereby granted,
     10 provided that the above copyright notice appear in all copies and that
     11 both that copyright notice and this permission notice appear in
     12 supporting documentation, and that the names of Digital, FUJITSU
     13 LIMITED and Sony Corporation not be used in advertising or publicity
     14 pertaining to distribution of the software without specific, written
     15 prior permission.
     16 
     17 DIGITAL, FUJITSU LIMITED AND SONY CORPORATION DISCLAIMS ALL WARRANTIES
     18 WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
     19 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL, FUJITSU LIMITED
     20 AND SONY CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     21 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
     22 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
     23 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     24 PERFORMANCE OF THIS SOFTWARE.
     25 
     26   Author: Hiroyuki Miyamoto  Digital Equipment Corporation
     27                              miyamoto (at) jrd.dec.com
     28   Modifier: Takashi Fujiwara FUJITSU LIMITED
     29 			     fujiwara (at) a80.tech.yk.fujitsu.co.jp
     30 	    Makoto Wakamatsu Sony Corporation
     31 		 	     makoto (at) 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 
     66 typedef enum {
     67     XimCbSuccess,
     68     XimCbNoCallback,
     69     XimCbError,
     70     XimCbQueued,
     71     XimCbBadContextID,
     72     XimCbBadOpcode
     73 } XimCbStatus;
     74 
     75 typedef 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 
     91 static XimCbStatus _XimGeometryCallback(Xim, Xic, char*, int);
     92 static XimCbStatus _XimStrConversionCallback(Xim, Xic, char*, int);
     93 static XimCbStatus _XimPreeditStartCallback(Xim, Xic, char*, int);
     94 static XimCbStatus _XimPreeditDoneCallback(Xim, Xic, char*, int);
     95 static void _free_memory_for_text(XIMText*);
     96 static XimCbStatus _XimPreeditDrawCallback(Xim, Xic, char*, int);
     97 static XimCbStatus _XimPreeditCaretCallback(Xim, Xic, char*, int);
     98 static XimCbStatus _XimStatusStartCallback(Xim, Xic, char*, int);
     99 static XimCbStatus _XimStatusDoneCallback(Xim, Xic, char*, int);
    100 static XimCbStatus _XimStatusDrawCallback(Xim, Xic, char*, int);
    101 static 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  */
    113 static 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 
    137 static Bool
    138 _XimIsReadyForProcess(Xic ic)
    139 {
    140     return(!ic->private.proto.waitCallback); /* check HM */
    141 }
    142 
    143 static 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 
    160 static 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 
    181 Bool
    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 
    260 static 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 
    283 static 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 
    368 static 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 
    417 static 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 
    440 static 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 
    554 static 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 
    564 static 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 
    595 static 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 
    647 static 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 
    670 static 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 
    693 static 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 
    728 static 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