#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "Xlibint.h"
#include "Xlcint.h"
#include "Ximint.h"
#include "XlcPubI.h"
#ifdef X_LOCALE
#define mblen(a,b) _Xmblen(a,b)
extern int _Xmblen ();
#endif
#define sz_CARD8 1
#define sz_INT8 1
#define sz_CARD16 2
#define sz_INT16 2
#define sz_BITMASK16 sz_CARD16
#define sz_CARD32 4
#define sz_INT32 4
#define sz_BITMASK32 sz_CARD32
#define sz_XIMID sizeof(XIMID)
#define sz_XICID sizeof(XICID)
#define sz_XIMATTRID sizeof(XIMATTRID)
#define sz_XICATTRID sizeof(XICATTRID)
#define sz_ximPacketHeader (XIM_HEADER_SIZE + sz_XIMID + sz_XICID)
#define sz_ximGeometry 0
#define sz_ximStrConversion (sz_CARD32 + sz_CARD32 + sz_CARD32 + sz_CARD32)
#define sz_ximPreeditStart 0
#define sz_ximPreeditStartReply sz_INT32
#define sz_ximPreeditCaret (sz_INT32 + sz_CARD32 + sz_CARD32)
#define sz_ximPreeditCaretReply sz_CARD32
#define sz_ximPreeditDone 0
#define sz_ximStatusStart 0
#define sz_ximStatusDone 0
typedef enum {
XimCbSuccess,
XimCbNoCallback,
XimCbError,
XimCbQueued,
XimCbBadContextID,
XimCbBadOpcode
} XimCbStatus;
typedef XimCbStatus (*XimCb)(
Xim, Xic, char*, int
);
#define PACKET_TO_MAJOROPCODE(p) (*(CARD8*)((CARD8*)(p)))
#define PACKET_TO_MINOROPCODE(p) (*(CARD8*)((CARD8*)(p) + sz_CARD8))
#define PACKET_TO_LENGTH(p) (*(CARD16*)((CARD8*)(p) + sz_CARD8 + sz_CARD8))
#define PACKET_TO_IMID(p) (*(XIMID*)((CARD8*)(p) + XIM_HEADER_SIZE))
#define PACKET_TO_ICID(p) (*(XICID*)((CARD8*)(p) + XIM_HEADER_SIZE + sz_XIMID))
#define _XimWriteData(im,len,data) \
(im->private.proto.write((im),(len),(XPointer)(data)))
#define _XimReadData(im,buf,buf_len,len) \
(im->private.proto.read((im),(XPointer)(buf),(buf_len),&(len)))
#define _XimFlushData(im) im->private.proto.flush((im))
Private XimCbStatus _XimGeometryCallback(Xim, Xic, char*, int);
Private XimCbStatus _XimStrConversionCallback(Xim, Xic, char*, int);
Private XimCbStatus _XimPreeditStartCallback(Xim, Xic, char*, int);
Private XimCbStatus _XimPreeditDoneCallback(Xim, Xic, char*, int);
Private void _free_memory_for_text(XIMText*);
Private XimCbStatus _XimPreeditDrawCallback(Xim, Xic, char*, int);
Private XimCbStatus _XimPreeditCaretCallback(Xim, Xic, char*, int);
Private XimCbStatus _XimStatusStartCallback(Xim, Xic, char*, int);
Private XimCbStatus _XimStatusDoneCallback(Xim, Xic, char*, int);
Private XimCbStatus _XimStatusDrawCallback(Xim, Xic, char*, int);
Private XimCbStatus _XimPreeditStateNotifyCallback(Xim, Xic, char *, int);
#if defined(__STDC__) && ((defined(sun) && defined(SVR4)) || defined(WIN32))
#define RConst
#else
#define RConst const
#endif
static RConst XimCb callback_table[] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
_XimGeometryCallback,
_XimStrConversionCallback,
NULL,
_XimPreeditStartCallback,
NULL,
_XimPreeditDrawCallback,
_XimPreeditCaretCallback,
NULL,
_XimPreeditDoneCallback,
_XimStatusStartCallback,
_XimStatusDrawCallback,
_XimStatusDoneCallback,
_XimPreeditStateNotifyCallback
};
Private Bool
_XimIsReadyForProcess(Xic ic)
{
return(!ic->private.proto.waitCallback);
}
Private void
_XimProcessPendingCallbacks(Xic ic)
{
XimPendingCallback pcbq;
while (((pcbq = ic->private.proto.pend_cb_que) != (XimPendingCallback)NULL)
&& _XimIsReadyForProcess(ic)) {
(void) (*callback_table[pcbq->major_opcode])(pcbq->im,
pcbq->ic,
pcbq->proto,
pcbq->proto_len);
ic->private.proto.pend_cb_que = pcbq->next;
Xfree(pcbq->proto);
Xfree(pcbq);
}
}
Private void
_XimPutCbIntoQueue(Xic ic, XimPendingCallback call_data)
{
XimPendingCallback pcbq = ic->private.proto.pend_cb_que;
while (pcbq != (XimPendingCallback)NULL) {
if (pcbq->next == (XimPendingCallback)NULL) {
break;
}
pcbq = pcbq->next;
}
if (pcbq == (XimPendingCallback)NULL) {
ic->private.proto.pend_cb_que = call_data;
}
else {
pcbq->next = call_data;
}
}
Public Bool
_XimCbDispatch(Xim xim,
INT16 len,
XPointer data,
XPointer call_data)
{
int major_opcode = PACKET_TO_MAJOROPCODE(data);
XIMID imid = PACKET_TO_IMID(data);
XICID icid = PACKET_TO_ICID(data);
Xim im = (Xim)call_data;
Xic ic = _XimICOfXICID(im, icid);
char* proto;
int proto_len;
if ((imid != im->private.proto.imid) || !ic) {
return False;
}
_XimProcessPendingCallbacks(ic);
if (major_opcode > 82) {
return False;
}
if (!callback_table[major_opcode]) {
return False;
}
proto = (char*)data + sz_ximPacketHeader;
proto_len = (int)len - sz_ximPacketHeader;
if (!_XimIsReadyForProcess(ic)) {
XimPendingCallback pcb;
char *proto_buf = (proto_len > 0) ? (char*)Xmalloc(proto_len) : NULL;
pcb = (XimPendingCallback)Xmalloc(sizeof(XimPendingCallbackRec));
if (pcb && (proto_len <= 0 || proto_buf)) {
if (proto_len > 0)
memcpy(proto_buf, proto, proto_len);
pcb->major_opcode = major_opcode;
pcb->im = im;
pcb->ic = ic;
pcb->proto = proto_buf;
pcb->proto_len = proto_len;
pcb->next = (XimPendingCallback)NULL;
_XimPutCbIntoQueue(ic, pcb);
} else {
}
}
else {
(void) (*callback_table[major_opcode])(im, ic, proto, proto_len);
}
return True;
}
Private XimCbStatus
_XimGeometryCallback(Xim im,
Xic ic,
char* proto,
int len)
{
XICCallback* cb = &ic->core.geometry_callback;
if (cb && cb->callback) {
(*cb->callback)((XIC)ic, cb->client_data, (XPointer)NULL);
}
else {
return XimCbNoCallback;
}
return XimCbSuccess;
}
Private XimCbStatus
_XimStrConversionCallback(Xim im,
Xic ic,
char* proto,
int len)
{
XICCallback* cb = &ic->core.string_conversion_callback;
XIMStringConversionCallbackStruct cbrec;
if (cb && cb->callback) {
int p = XIM_HEADER_SIZE;
cbrec.position = (XIMStringConversionPosition)
*(CARD32*)&proto[p]; p += sz_CARD32;
cbrec.direction = (XIMCaretDirection)
*(CARD32*)&proto[p]; p += sz_CARD32;
cbrec.operation = (XIMStringConversionOperation)
*(CARD32*)&proto[p]; p += sz_CARD32;
cbrec.factor = (unsigned short)
*(CARD32*)&proto[p];
(*cb->callback)((XIC)ic, cb->client_data, (XPointer)&cbrec);
}
else {
_XimError(im, ic,
(CARD16)XIM_BadSomething,
(INT16)len,
(CARD16)XIM_STR_CONVERSION,
(char*)proto);
return XimCbNoCallback;
}
{
CARD8 *buf;
INT16 buf_len;
int p, length_in_bytes, i;
{
length_in_bytes = (cbrec.text->encoding_is_wchar)?
sizeof(wchar_t) * cbrec.text->length:
strlen(cbrec.text->string.mbs);
buf_len = XIM_HEADER_SIZE +
sz_CARD16 +
2 + length_in_bytes +
XIM_PAD(2 + length_in_bytes) +
2 + 2 + sz_CARD32 * cbrec.text->length;
buf = (CARD8*)Xmalloc(buf_len);
}
_XimSetHeader((XPointer)buf, XIM_STR_CONVERSION_REPLY, 0, &buf_len);
buf_len -= XIM_HEADER_SIZE;
p = XIM_HEADER_SIZE;
*(CARD16*)&buf[p] = (CARD16)im->private.proto.imid; p += sz_CARD16;
*(CARD16*)&buf[p] = (CARD16)ic->private.proto.icid; p += sz_CARD16;
*(CARD16*)&buf[p] = (CARD16)cbrec.text->length; p += sz_CARD16;
memcpy(&buf[p],&cbrec.text->string.mbs,length_in_bytes);
p += length_in_bytes;
*(CARD16*)&buf[p] = (CARD16)(sz_CARD32*cbrec.text->length);
p += XIM_PAD(2);
for (i = 0; i < (int)cbrec.text->length; i++) {
*(CARD32*)&buf[p] = (CARD32)cbrec.text->feedback[i];
p += sz_CARD32;
}
if (!(_XimWriteData(im, buf_len, buf))) {
return XimCbError;
}
_XimFlushData(im);
Xfree(buf);
}
return XimCbSuccess;
}
Private XimCbStatus
_XimPreeditStartCallback(Xim im,
Xic ic,
char* proto,
int len)
{
XICCallback* cb = &ic->core.preedit_attr.start_callback;
int ret;
if (cb && cb->callback){
ret = (*(cb->callback))((XIC)ic, cb->client_data, (XPointer)NULL);
}
else {
_XimError(im, ic,
(CARD16)XIM_BadSomething,
(INT16)len,
(CARD16)XIM_PREEDIT_START,
(char*)proto);
return XimCbNoCallback;
}
{
CARD32 buf32[(sz_ximPacketHeader + sz_ximPreeditStartReply) / 4];
CARD8 *buf = (CARD8 *)buf32;
INT16 buf_len = sz_XIMID + sz_XICID + sz_ximPreeditStartReply;
int p;
_XimSetHeader((XPointer)buf, XIM_PREEDIT_START_REPLY, 0, &buf_len);
p = XIM_HEADER_SIZE;
*(CARD16*)&buf[p] = (CARD16)im->private.proto.imid; p += sz_CARD16;
*(CARD16*)&buf[p] = (CARD16)ic->private.proto.icid; p += sz_CARD16;
*(INT32*)&buf[p] = (INT32)ret;
if (!(_XimWriteData(im, buf_len, buf))) {
return XimCbError;
}
_XimFlushData(im);
}
return XimCbSuccess;
}
Private XimCbStatus
_XimPreeditDoneCallback(Xim im,
Xic ic,
char* proto,
int len)
{
XICCallback* cb = &ic->core.preedit_attr.done_callback;
if (cb && cb->callback) {
(*cb->callback)((XIC)ic, cb->client_data, (XPointer)NULL);
}
else {
return XimCbNoCallback;
}
return XimCbSuccess;
}
Private void
_read_text_from_packet(Xim im,
char* buf,
XIMText** text_ptr)
{
int status;
XIMText* text;
int tmp_len;
char* tmp_buf;
Status s = 0;
status = (int)*(BITMASK32*)buf; buf += sz_BITMASK32;
if (status & 0x00000001) {
buf += sz_CARD16;
buf += 2;
*text_ptr = (XIMText*)NULL;
return;
}
*text_ptr = text = (XIMText*)Xmalloc(sizeof(XIMText));
if (text == (XIMText*)NULL) return;
tmp_len = (int)*(CARD16*)buf;
buf += sz_CARD16;
if ((tmp_buf = (char*)Xmalloc(tmp_len + 1))) {
memcpy(tmp_buf, buf, tmp_len);
tmp_buf[tmp_len] = '\0';
text->encoding_is_wchar = False;
text->length = im->methods->ctstombs((XIM)im,
tmp_buf, tmp_len,
NULL, 0, &s);
if (s != XLookupNone) {
#ifndef NO_DEC_I18N_FIX
if ((text->string.multi_byte =
(char*)Xmalloc(text->length *
XLC_PUBLIC(im->core.lcd,mb_cur_max) + 1))) {
#else
if (text->string.multi_byte = (char*)Xmalloc(text->length+1)) {
#endif
int tmp;
#ifndef NO_DEC_I18N_FIX
char *char_tmp;
int char_len;
#endif
tmp = im->methods->ctstombs((XIM)im,
tmp_buf, tmp_len,
#ifndef NO_DEC_I18N_FIX
text->string.multi_byte,
text->length * XLC_PUBLIC(im->core.lcd,mb_cur_max) + 1,
#else
text->string.multi_byte, text->length,
#endif
&s);
text->string.multi_byte[tmp] = '\0';
#ifndef NO_DEC_I18N_FIX
text->length = 0;
char_tmp = text->string.multi_byte;
while (*char_tmp != '\0') {
char_len = mblen(char_tmp, strlen(char_tmp));
char_tmp = char_tmp + char_len;
(text->length)++;
}
#endif
}
}
else {
text->length = 0;
text->string.multi_byte = NULL;
}
Xfree(tmp_buf);
}
buf += tmp_len;
buf += XIM_PAD(sz_CARD16 + tmp_len);
if (status & 0x00000002) {
text->feedback = (XIMFeedback*)NULL;
}
else {
int i, j;
i = (int)*(CARD16*)buf; buf += sz_CARD16;
buf += sz_CARD16;
text->feedback = (XIMFeedback*)Xmalloc(i*(sizeof(XIMFeedback)/sizeof(CARD32)));
j = 0;
while (i > 0) {
text->feedback[j] = (XIMFeedback)*(CARD32*)buf;
buf += sz_CARD32;
i -= sz_CARD32;
j++;
}
if (status & 0x00000001) {
text->length = j;
}
}
}
Private void
_free_memory_for_text(XIMText* text)
{
if (text) {
if (text->string.multi_byte)
Xfree(text->string.multi_byte);
if (text->feedback)
Xfree(text->feedback);
Xfree(text);
}
}
Private XimCbStatus
_XimPreeditDrawCallback(Xim im,
Xic ic,
char* proto,
int len)
{
XICCallback* cb = &ic->core.preedit_attr.draw_callback;
XIMPreeditDrawCallbackStruct cbs;
if (cb && cb->callback) {
cbs.caret = (int)*(INT32*)proto; proto += sz_INT32;
cbs.chg_first = (int)*(INT32*)proto; proto += sz_INT32;
cbs.chg_length = (int)*(INT32*)proto; proto += sz_INT32;
_read_text_from_packet(im, proto, &cbs.text);
(*cb->callback)((XIC)ic, cb->client_data, (XPointer)&cbs);
_free_memory_for_text((XIMText*)cbs.text);
}
else {
return XimCbNoCallback;
}
return XimCbSuccess;
}
Private XimCbStatus
_XimPreeditCaretCallback(Xim im,
Xic ic,
char* proto,
int len)
{
XICCallback* cb = &ic->core.preedit_attr.caret_callback;
XIMPreeditCaretCallbackStruct cbs;
if (cb && cb->callback) {
cbs.position = (int)*(INT32*)proto; proto += sz_INT32;
cbs.direction = (XIMCaretDirection)*(CARD32*)proto; proto += sz_CARD32;
cbs.style = (XIMCaretStyle)*(CARD32*)proto; proto += sz_CARD32;
(*cb->callback)((XIC)ic, cb->client_data, (XPointer)&cbs);
}
else {
_XimError(im, ic,
(CARD16)XIM_BadSomething,
(INT16)len,
(CARD16)XIM_PREEDIT_CARET,
(char*)proto);
return XimCbNoCallback;
}
{
CARD8 buf[sz_ximPacketHeader + sz_ximPreeditCaretReply];
INT16 len = sz_XIMID + sz_XICID + sz_ximPreeditCaretReply;
int p;
_XimSetHeader((XPointer)buf, XIM_PREEDIT_CARET_REPLY, 0, &len);
p = XIM_HEADER_SIZE;
*(CARD16*)&buf[p] = (CARD16)im->private.proto.imid; p += sz_CARD16;
*(CARD16*)&buf[p] = (CARD16)ic->private.proto.icid; p += sz_CARD16;
*(CARD32*)&buf[p] = (CARD32)cbs.position;
if (!(_XimWriteData(im, len, buf))) {
return XimCbError;
}
_XimFlushData(im);
}
return XimCbSuccess;
}
Private XimCbStatus
_XimStatusStartCallback(Xim im,
Xic ic,
char* proto,
int len)
{
XICCallback* cb = &ic->core.status_attr.start_callback;
if (cb && cb->callback) {
(*cb->callback)((XIC)ic, cb->client_data, (XPointer)NULL);
}
else {
return XimCbNoCallback;
}
return XimCbSuccess;
}
Private XimCbStatus
_XimStatusDoneCallback(Xim im,
Xic ic,
char* proto,
int len)
{
XICCallback* cb = &ic->core.status_attr.done_callback;
if (cb && cb->callback) {
(*cb->callback)((XIC)ic, cb->client_data, (XPointer)NULL);
}
else {
return XimCbNoCallback;
}
return XimCbSuccess;
}
Private XimCbStatus
_XimStatusDrawCallback(Xim im,
Xic ic,
char* proto,
int len)
{
XICCallback* cb = &ic->core.status_attr.draw_callback;
XIMStatusDrawCallbackStruct cbs;
if (cb && cb->callback) {
cbs.type = (XIMStatusDataType)*(CARD32*)proto; proto += sz_CARD32;
if (cbs.type == XIMTextType) {
_read_text_from_packet(im, proto, &cbs.data.text);
}
else if (cbs.type == XIMBitmapType) {
cbs.data.bitmap = (Pixmap)*(CARD32*)proto;
}
(*cb->callback)((XIC)ic, cb->client_data, (XPointer)&cbs);
if (cbs.type == XIMTextType)
_free_memory_for_text((XIMText *)cbs.data.text);
}
else {
return XimCbNoCallback;
}
return XimCbSuccess;
}
Private XimCbStatus
_XimPreeditStateNotifyCallback( Xim im, Xic ic, char* proto, int len )
{
XICCallback *cb = &ic->core.preedit_attr.state_notify_callback;
if( cb && cb->callback ) {
XIMPreeditStateNotifyCallbackStruct cbrec;
cbrec.state = *(BITMASK32 *)proto;
(*cb->callback)( (XIC)ic, cb->client_data, (XPointer)&cbrec );
}
else {
return XimCbNoCallback;
}
return XimCbSuccess;
}