// XIMプロトコルのパケットを下位層から受けとり、
// それをディスパッチする。
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include "xim.h"
#ifndef __GNUC__
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# endif
#endif
//色々な表
input_style input_style_tab[]={
{XIMPreeditNothing|XIMStatusNothing, IS_ROOT_WINDOW},
//{XIMPreeditPosition|XIMStatusArea, IS_OVER_THE_SPOT},// emacs
{XIMPreeditPosition|XIMStatusNothing, IS_OVER_THE_SPOT},
//{XIMPreeditCallbacks|XIMStatusCallbacks, IS_ON_THE_SPOT},// OOo
//{XIMPreeditArea|XIMStatusArea, IS_ROOT_WINDOW},
{XIMPreeditCallbacks|XIMStatusNothing, IS_ON_THE_SPOT},
{0, 0},
};
// XIMPreeditArea,XIMPreeditCallbacks,XIMPreeditPosition
// XIMPreeditNothing,XIMPreeditNone
// XIMStatusArea,XIMStatusCallbacks
// XIMStatusNothing,XIMStatusNone
static char *xim_packet_name[]={
// 0
0,"XIM_CONNECT","XIM_CONNECT_REPLY",
"XIM_DISCONNECT","XIM_DISCONNECT_REPLY",
0,0,0,0,0,
// 10
"XIM_AUTH_REQUIRED","XIM_AUTH_REPLY","XIM_AUTH_NEXT",
"XIM_AUTH_SETUP","XIM_AUTH_NG",0,0,0,0,0,
// 20
"XIM_ERROR",0,0,0,0,0,0,0,0,0,
// 30
"XIM_OPEN","XIM_OPEN_REPLY","XIM_CLOSE",
"XIM_CLOSE_REPLY","XIM_REGISTER_TRIGGERKEYS",
"XIM_TRIGGER_NOTIFY","XIM_TRIGGER_NOTIFY_REPLY",
"XIM_SET_EVENT_MASK","XIM_ENCODING_NEGOTIATION",
"XIM_ENCODING_NEGOTIATION_REPLY",
// 40
"XIM_QUERY_EXTENSION","XIM_QUERY_EXTENSION_REPLY",
"XIM_SET_IM_VALUES","XIM_SET_IM_VALUES_REPLY",
"XIM_GET_IM_VALUES","XIM_GET_IM_VALUES_REPLY",
0,0,0,0,
// 50
"XIM_CREATE_IC","XIM_CREATE_IC_REPLY",
"XIM_DESTROY_IC","XIM_DESTROY_IC_REPLY",
"XIM_SET_IC_VALUES","XIM_SET_IC_VALUES_REPLY",
"XIM_GET_IC_VALUES","XIM_GET_IC_VALUES_REPLY",
"XIM_SET_IC_FOCUS","XIM_UNSET_FOCUS",
// 60
"XIM_FORWARD_EVENT","XIM_SYNC","XIM_SYNC_REPLY",
"XIM_COMMIT","XIM_RESET_IC","XIM_RESET_IC_REPLY",
0,0,0,0,
// 70
"XIM_GEOMETRY","XIM_STR_CONVERSION",
"XIM_STR_CONVERSION_REPLY","XIM_PREEDIT_START",
"XIM_PREEDIT_START_REPLY","XIM_PREEDIT_DRAW",
"XIM_PREEDIT_CARET","XIM_PREEDIT_CARET_REPLY",
"XIM_PREEDIT_DONE","XIM_STATUS_START",
// 80
"XIM_STATUS_DRAW","XIM_STATUS_DONE","XIM_PREEDITSTATE"
};
static struct XIMATTRIBUTE{
XIMATTRIBUTE(char *n,int t);
static void write_imattr_to_packet(TxPacket *p);
char *name;
int type;
}xim_attributes[]={
XIMATTRIBUTE(XNQueryInputStyle,TYPE_XIMSTYLE),
};
XIMATTRIBUTE::XIMATTRIBUTE(char *n, int t)
{
name = n;
type = t;
}
void XIMATTRIBUTE::write_imattr_to_packet(TxPacket *p)
{
int i,l;
char tmp[4];
for (i = 0; i < 4; i++) {
tmp[i] = 0;
}
for (i = 0, l =0; i < (int)(sizeof(xim_attributes)/sizeof(XIMATTRIBUTE));
i++) {
l += 6;
l += strlen(xim_attributes[i].name);
l += pad4(strlen(xim_attributes[i].name)+2);
}
p->pushC16(l);
for (i = 0; i < (int)(sizeof(xim_attributes)/sizeof(XIMATTRIBUTE)); i++){
p->pushC16((unsigned int)i);
p->pushC16((unsigned int)xim_attributes[i].type);
p->pushC16((unsigned int)strlen(xim_attributes[i].name));
p->pushBytes(xim_attributes[i].name,
strlen(xim_attributes[i].name));
p->pushBytes(tmp, pad4(strlen(xim_attributes[i].name))+2);
}
}
static struct XICATTRIBUTE{
XICATTRIBUTE(char *n, int t);
static void write_icattr_to_packet(TxPacket *p);
char *name;
int type;
}xic_attributes[]={
//この順番とximpn.hで定義している番号は一致していないといけない
//ktermとgtkでルートウィンドウスタイルのとき
XICATTRIBUTE(XNInputStyle, TYPE_LONG),
XICATTRIBUTE(XNClientWindow, TYPE_WINDOW),
XICATTRIBUTE(XNFocusWindow, TYPE_WINDOW),
//ktermでover the spotを行うとき
XICATTRIBUTE(XNPreeditAttributes, TYPE_NESTEDLIST),
XICATTRIBUTE(XNForeground, TYPE_LONG),
XICATTRIBUTE(XNBackground, TYPE_LONG),
XICATTRIBUTE(XNSpotLocation, TYPE_POINT),
XICATTRIBUTE(XNFontSet, TYPE_XFONTSET),
XICATTRIBUTE(XNArea, TYPE_XRECTANGLE),
XICATTRIBUTE(XNLineSpace, TYPE_WORD),
//
XICATTRIBUTE(XNStatusAttributes, TYPE_NESTEDLIST),
XICATTRIBUTE(XNAreaNeeded, TYPE_XRECTANGLE),
XICATTRIBUTE(XNColormap, TYPE_WORD),
XICATTRIBUTE(XNStdColormap, TYPE_WORD),
XICATTRIBUTE(XNBackgroundPixmap, TYPE_LONG),
XICATTRIBUTE(XNCursor, TYPE_WORD),
XICATTRIBUTE(XNFilterEvents, TYPE_WORD),
XICATTRIBUTE(XNSeparatorofNestedList, TYPE_SEPARATOR),
};
XICATTRIBUTE::XICATTRIBUTE(char *n, int t)
{
name = n;
type = t;
}
void XICATTRIBUTE::write_icattr_to_packet(TxPacket *p)
{
int i,l;
char tmp[4];
for (i = 0; i < 4; i++) {
tmp[i] = 0;
}
for (i = 0, l = 0; i < (int)(sizeof(xic_attributes)/sizeof(XICATTRIBUTE)) ;
i++){
l += 6;
l += strlen(xic_attributes[i].name);
l += pad4(strlen(xic_attributes[i].name)+2);
}
p->pushC16(l);
p->pushC16(0);
for (i = 0; i < (int)(sizeof(xic_attributes)/sizeof(XICATTRIBUTE)); i++) {
p->pushC16((unsigned int)i);
p->pushC16((unsigned int)xic_attributes[i].type);
p->pushC16((unsigned int)strlen(xic_attributes[i].name));
p->pushBytes(xic_attributes[i].name,
strlen(xic_attributes[i].name));
p->pushBytes(tmp, pad4(strlen(xic_attributes[i].name)+2));
}
}
void force_event(Window w)
{
Window fw;
int rev;
XGetInputFocus(gDpy, &fw, &rev);
XSetInputFocus(gDpy, w, rev, CurrentTime);
XSetInputFocus(gDpy, fw, rev, CurrentTime);
XFlush(gDpy);
}
Connection::Connection()
{
mIsCloseWait = false;
mByteorder = BYTEORDER_UNKNOWN;
}
Connection::~Connection()
{
//自分で作ったIMを全てこわす。
std::list<int>::iterator i;
for (i = mCreatedIm.begin(); i != mCreatedIm.end(); i++) {
close_im(*i);
}
//
std::list<RxPacket *>::iterator ir;
for (ir = mRxQ.begin(); ir != mRxQ.end(); ir ++) {
delete *ir;
}
std::list<TxPacket *>::iterator it;
for (it = mTxQ.begin(); it != mTxQ.end(); it ++) {
delete *it;
}
for (it = mPTxQ.begin(); it != mPTxQ.end(); it ++) {
delete *it;
}
}
void Connection::terminate()
{
mIsCloseWait = true;
}
void Connection::OnRecv()
{
std::list<RxPacket *>::iterator i;
i = mRxQ.begin();
if (i != mRxQ.end()) {
int major = (*i)->getMajor();
//一通りそろったら、プロトコルの番号順に並びかえたい。
RxPacket *p = *i;
if (g_option_mask & OPT_TRACE_XIM) {
printf("<-: %s(%d,%d).\n", xim_packet_name[major],
p->getC16(), p->getC16());
p->rewind();
}
switch(major){
case XIM_CONNECT:
xim_connect(p);
break;
case XIM_OPEN:
xim_open(p);
break;
case XIM_QUERY_EXTENSION:
xim_query_extension(p);
break;
case XIM_ENCODING_NEGOTIATION:
xim_encoding_negotiation(p);
break;
case XIM_CLOSE:
xim_close(p);
break;
case XIM_DISCONNECT:
xim_disconnect(p);
break;
case XIM_GET_IM_VALUES:
xim_get_im_values(p);
break;
case XIM_SET_IC_VALUES:
xim_set_ic_values(p);
break;
case XIM_GET_IC_VALUES:
xim_get_ic_values(p);
break;
case XIM_CREATE_IC:
xim_create_ic(p);
break;
case XIM_DESTROY_IC:
xim_destroy_ic(p);
break;
case XIM_SET_IC_FOCUS:
xim_set_ic_focus(p);
break;
case XIM_UNSET_IC_FOCUS:
xim_unset_ic_focus(p);
break;
case XIM_TRIGGER_NOTIFY:
//xim_trigger_notify(*i);トリガーなんかは使わん。
break;
case XIM_FORWARD_EVENT:
xim_forward_event(p);
break;
case XIM_SYNC_REPLY:
//xim_sync_reply(p);
break;
case XIM_RESET_IC:
xim_reset_ic(p);
break;
case XIM_PREEDIT_START_REPLY:
// do nothing
break;
case XIM_PREEDIT_CARET_REPLY:
// do nothing
break;
case XIM_ERROR:
xim_error(p);
break;
default:
printf("Unknown(or not implemented.) packet from xim connection.\n");
(*i)->dump();
break;
}
mRxQ.pop_front();
delete p;
}
}
void Connection::OnSend()
{
std::list<int>::iterator i;
for (i = mCreatedIm.begin(); i != mCreatedIm.end(); i++) {
XimIM *im;
im = get_im_by_id(*i);
if (im) {
im->onSendPacket();
}
}
}
void Connection::OnClose()
{
std::list<int>::iterator i;
for (i = mCreatedIm.begin(); i != mCreatedIm.end(); i++) {
close_im(*i);
}
mCreatedIm.erase(mCreatedIm.begin(), mCreatedIm.end());
}
void Connection::push_packet(TxPacket *p)
{
OnPushPacket();
mTxQ.push_back(p);
if (g_option_mask & OPT_TRACE_XIM) {
printf("->: %s.\n", xim_packet_name[p->get_major()]);
}
}
void Connection::push_passive_packet(TxPacket *p)
{
mPTxQ.push_back(p);
if (g_option_mask & OPT_TRACE_XIM) {
printf("(->): %s.\n", xim_packet_name[p->get_major()]);
}
}
void Connection::push_error_packet(int imid, int icid, int er, char *str)
{
TxPacket *t;
t = createTxPacket(XIM_ERROR,0);
t->pushC16(imid);
t->pushC16(icid);
int m = 0;
if (imid) {
m+=1;
}
if (icid) {
m+=2;
}
t->pushC16(m);
t->pushC16(er);
int l=strlen(str);
char tmp[4];
t->pushC16(l);
t->pushC16(0);
t->pushBytes(str, l);
t->pushBytes(tmp, pad4(l));
push_packet(t);
}
unsigned short Connection::to_hs(unsigned short s)
{
if (host_byte_order == mByteorder) {
return s;
}
unsigned char *v;
v = (unsigned char *)&s;
s = (v[0]<<8) + v[1];
return s;
}
unsigned int Connection::to_hl(unsigned int l)
{
if (host_byte_order == mByteorder) {
return l;
}
return l;
}
//
// Packet handlers
//
void Connection::xim_connect(RxPacket *p)
{
TxPacket *t;
p->rewind();
p->getC8();
p->getC8(); //discard
if (p->isOverRun()) {
push_error_packet(0, 0, 0, "Invalid Packet");
terminate();
return ;
}
t = createTxPacket(XIM_CONNECT_REPLY, 0);
t->pushC16(1);
t->pushC16(0);
push_packet(t);
if (g_option_mask & OPT_TRACE) {
printf("accept xim connection.\n");
}
}
void Connection::xim_disconnect(RxPacket *p)
{
TxPacket *t;
t = createTxPacket(XIM_DISCONNECT_REPLY,0);
push_packet(t);
//
terminate();
if (g_option_mask & OPT_TRACE) {
printf("disconnect xim connection.\n");
}
}
void Connection::xim_open(RxPacket *p)
{
char buf[16];
int l;
for (l = 0; l < 16; l++) {
buf[l] = 0;
}
l = p->getStr8Len();
if (l > 15) {
printf("too long locale name.\n");
return ;
}
p->getStr8(buf);
TxPacket *t;
int imid;
imid = unused_im_id();
mCreatedIm.push_back(imid);//作ったやつが責任もって破棄する。
create_im(this, imid);
t = createTxPacket(XIM_OPEN_REPLY, 0);
t->pushC16(imid);
XIMATTRIBUTE::write_imattr_to_packet(t);
XICATTRIBUTE::write_icattr_to_packet(t);
push_packet(t);
// イベントマスクの選択
t = createTxPacket(XIM_SET_EVENT_MASK, 0);
t->pushC16(imid);
t->pushC16(0);
t->pushC32(KeyPressMask);
t->pushC32(KeyPressMask);
push_packet(t);
}
void Connection::xim_close(RxPacket *p)
{
int imid;
imid = p->getC16();
TxPacket *t;
t = createTxPacket(XIM_CLOSE_REPLY,0);
t->pushC16(imid);
t->pushC16(0);
push_packet(t);
close_im(imid);
std::list<int>::iterator i;
for (i = mCreatedIm.begin(); i != mCreatedIm.end(); i++) {
if (*i == imid) {
mCreatedIm.erase(i);
return;
}
}
}
void Connection::xim_query_extension(RxPacket *p)
{
int imid;
imid = p->getC16();
TxPacket *t;
t = createTxPacket(XIM_QUERY_EXTENSION_REPLY, 0);
t->pushC16(imid);
t->pushC16(0);
push_packet(t);
}
void Connection::xim_encoding_negotiation(RxPacket *p)
{
TxPacket *t;
t = createTxPacket(XIM_ENCODING_NEGOTIATION_REPLY,0);
C16 l, m, s;
int i, idx, index;
int imid;
char buf[32];
imid = p->getC16(); // m_imid
l = p->getC16();
index = 0;
for (m = 0, s = 0, idx = 0; m < l; m += (s+1), idx ++) {
s = p->getStr8Len ();
for (i= 0; i < 32; i++) {
buf[i] = 0;
}
p->getStr8 (buf);
/* COMPOUND_TEXT (eucJP is Buggy) */
if (!strcmp ("COMPOUND_TEXT", buf)) {
index = idx;
}
}
t->pushC16(imid);
t->pushC16(0);
t->pushC16(index);
t->pushC16(0);
push_packet(t);
}
void Connection::xim_get_im_values(RxPacket *p)
{
int l,i;
int imid;
TxPacket *t;
t = createTxPacket(XIM_GET_IM_VALUES_REPLY, 0);
imid = p->getC16(); // input-method id
l = p->getC16() / 2; //個数
int *ra = (int *)alloca(sizeof(int)*l);
int rlen = 0;
for (i = 0; i < l; i++) {
ra[i] = p->getC16();
rlen += 4;
}
// どうせIMAttributeは1種類しかないんだし、、
t->pushC16(imid);
t->pushC16(16); // length
// XIMATTRIBUTE
int nr_style;
for (nr_style = 0; input_style_tab[nr_style].style; nr_style ++);
t->pushC16(0); // attribute id
t->pushC16(nr_style*4); //length
t->pushC16(nr_style); // 個数
t->pushC16(0);
for (i = 0; i < nr_style; i++) {
t->pushC32(input_style_tab[i].x_style);
}
push_packet(t);
}
void Connection::xim_set_ic_values(RxPacket *p)
{
int imid, icid;
imid = p->getC16();
icid = p->getC16();
p->rewind();
XimIM *im = get_im_by_id(imid);
if (im) {
im->set_ic_values(p, icid);
}
TxPacket *t=createTxPacket(XIM_SET_IC_VALUES_REPLY,0);
t->pushC16(imid);
t->pushC16(icid);
push_packet(t);
}
void Connection::xim_get_ic_values(RxPacket *p)
{
int imid;
imid = p->getC16();
p->rewind();
XimIM *im;
im = get_im_by_id(imid);
if (im) {
im->get_ic_values(p);
}
}
void Connection::xim_create_ic(RxPacket *p)
{
XimIM *im;
int imid;
imid = p->getC16();
p->rewind();
im = get_im_by_id(imid);
if (im) {
im->create_ic(p);
}
}
void Connection::xim_destroy_ic(RxPacket *p)
{
int imid;
int icid;
imid = p->getC16();
icid = p->getC16();
XimIM *im = get_im_by_id(imid);
if (im) {
im->destroy_ic(icid);
}
TxPacket *t = createTxPacket(XIM_DESTROY_IC_REPLY,0);
t->pushC16(imid);
t->pushC16(icid);
push_packet(t);
}
void Connection::xim_set_ic_focus(RxPacket *p)
{
int imid;
XimIM *im;
imid = p->getC16();
im = get_im_by_id(imid);
if (im) {
im->set_ic_focus(p->getC16());
}
}
void Connection::xim_unset_ic_focus(RxPacket *p)
{
int imid;
XimIM *im;
imid = p->getC16();
im = get_im_by_id(imid);
if (im) {
im->unset_ic_focus(p->getC16());
}
}
void Connection::xim_forward_event(RxPacket *p)
{
int imid,icid;
imid = p->getC16();
icid = p->getC16();
p->rewind();
XimIM *im = get_im_by_id(imid);
if (im) {
im->forward_event(p);
}
TxPacket *t = createTxPacket(XIM_SYNC_REPLY,0);
t->pushC16(imid);
t->pushC16(icid);
push_packet(t);
}
void Connection::xim_reset_ic(RxPacket *p)
{
XimIC *ic = get_ic(p);
if (ic) {
ic->reset_ic();
}
}
void Connection::xim_error(RxPacket *p)
{
int imid,icid,mask,ecode,len;
char *buf;
imid = p->getC16();
icid = p->getC16();
mask = p->getC16();
ecode = p->getC16();
len = p->getStrLen();
buf = (char *)alloca(len+1);
buf[len] = 0;
p->getStr(buf);
printf("XIM_ERROR received.\n");
if (mask & 1) {
printf(" imid = %d\n", imid);
}
if (mask & 2) {
printf(" icid = %d\n", icid);
}
printf(" error_code = %d\n", ecode);
printf(" message=(%s)\n", buf);
}
XimIC *Connection::get_ic(RxPacket *p)
{
int imid,icid;
XimIM *im;
imid = p->getC16();
icid = p->getC16();
p->rewind();
im = get_im_by_id(imid);
if (im) {
return im->get_ic_by_id(icid);
}
return 0;
}
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1