// XIMプロトコルのパケットでIC(Input Context)に関わる物を処理する
// 特にキーが押されたというメッセージと文字をコミットするメッセージを
// 仮名漢字モジュールへとの間で仲介する。
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <ctype.h>
#include "xim.h"
#include "convdisp.h"
#include "kkconv.h"
#ifndef __GNUC__
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# endif
#endif
extern input_style input_style_tab[];
char invalid_style_msg[]=
"サポートしていない入力スタイルの\n"
"設定をクライアントが要求してきました。";
XimIC *XimIC::current_ic;
int XimIC::nrActiveIC;
pe_stat::pe_stat(KKContext *c)
{
cont = c;
clear();
}
void pe_stat::clear()
{
jstrings.erase(jstrings.begin(), jstrings.end());
cands = 0;
}
void pe_stat::new_segment(int s)
{
pe_jstring p;
p.stat = s;
jstrings.push_back(p);
}
void pe_stat::push_cchar(cchar c)
{
std::list<pe_jstring>::reverse_iterator i= jstrings.rbegin();
(*i).s.push_back(c);
}
int pe_stat::get_char_count()
{
std::list<pe_jstring>::iterator i;
jstring_t::iterator j;
int k=0;
for (i = jstrings.begin(); i != jstrings.end(); i++) {
for (j = (*i).s.begin(); j != (*i).s.end(); j++) {
k++;
}
}
return k;
}
icxatr::icxatr()
{
atr_mask = 0;
change_mask = 0;
font_set_name = NULL;
font_set = NULL;
foreground_pixel = BlackPixel(gDpy, DefaultScreen(gDpy));
background_pixel = WhitePixel(gDpy, DefaultScreen(gDpy));
}
icxatr::~icxatr()
{
if (font_set_name) {
free((void *)font_set_name);
XFreeFontSet(gDpy,font_set);
}
}
bool icxatr::has_atr(int id)
{
return atr_mask & (1<<id);
}
void icxatr::set_atr(int id, C8 *val, int len, int o)
{
switch (id) {
case ICA_InputStyle:
input_style = readC32(val,o);
break;
case ICA_ClientWindow:
client_window = readC32(val,o);
break;
case ICA_FocusWindow:
focus_window = readC32(val,o);
break;
case ICA_Foreground:
foreground_pixel = readC32(val,o);
break;
case ICA_Background:
background_pixel = readC32(val,o);
break;
case ICA_SpotLocation:
spot_location.x = readC16(val,o);
spot_location.y = readC16(&val[2],o);
break;
case ICA_FontSet:
{
int len = readC16(val,o);
char *new_fsn;
new_fsn = (char *)alloca(len+1);
new_fsn[len] = 0;
memcpy(new_fsn,&val[2],len);
if (font_set_name && !strcmp(new_fsn, font_set_name)) {
break;
}
if (font_set_name) {
free(font_set_name);
}
font_set_name = strdup(new_fsn);
char **missing,*def;
int nr_missing;
font_set = XCreateFontSet(gDpy,font_set_name,
&missing,&nr_missing,&def);
if (missing) {
XFreeStringList(missing);
}
}
break;
case ICA_Area:
{
area.x = readC16(&val[0],o);
area.y = readC16(&val[2],o);
area.width = readC16(&val[4],o);
area.height = readC16(&val[6],o);
}
break;
case ICA_LineSpace:
line_space=readC16(val,o);
break;
default:
//未知のアトリビュート
printf("try to set unknown ic attribute %d.\n",id);
return ;
}
atr_mask |= (1 << id);
change_mask |= (1 << id);
}
bool icxatr::is_changed(int id)
{
if (change_mask & (1<<id)) {
return true;
}
return false;
}
void icxatr::unset_change_mask(int id)
{
change_mask &=(~(1<<id));
}
void icxatr::print()
{
if (has_atr(ICA_InputStyle)) {
printf("input-style %ld.\n", input_style);
} else {
printf("input-style undefined.\n");
}
if (has_atr(ICA_ClientWindow)) {
printf("client-window id %ld.\n", client_window);
} else {
printf("client-window id undefined.\n");
}
if (has_atr(ICA_FocusWindow)) {
printf("focus-window id %ld.\n", focus_window);
}else{
printf("focus-window id undefined.\n");
}
/*Preedit Attributesは具体的な値を持ちません。*/
if (has_atr(ICA_Foreground)) {
printf("foreground-pixel %d.\n", foreground_pixel);
} else {
printf("foreground-pixel undefined.\n");
}
if (has_atr(ICA_Background)) {
printf("background-pixel %d.\n", background_pixel);
} else {
printf("background-pixel undefined.\n");
}
if (has_atr(ICA_SpotLocation)) {
printf("spot location x=%d,y=%d.\n",
spot_location.x, spot_location.y);
} else {
printf("spot location undefined.\n");
}
if (has_atr(ICA_FontSet)) {
printf("font-set-name %s\n", font_set_name);
} else {
printf("font-set-name undefined.\n");
}
if (has_atr(ICA_Area)) {
printf("area = x=%d y=%d width=%d height=%d.\n",
area.x, area.y, area.width, area.height);
} else {
printf("area undefined.\n");
}
if (has_atr(ICA_LineSpace)) {
printf("line-space %d.\n", line_space);
} else {
printf("line-space undefined.\n");
}
}
int icxatr::getSize(int id)
{
switch (id) {
case ICA_FocusWindow:
return 4;
case ICA_FilterEvents:
return 4;
}
return 0;
}
XimIC::XimIC(Connection *c, int imid, int icid)
{
m_conn = c;
mIMid = imid;
mICid = icid;
mIsActive = false;
m_kkContext = createKKContext(this);
mConvdisp = 0;
if (g_option_mask & OPT_TRACE) {
printf("imid=%d, icid=%d ic created.\n", mIMid, mICid);
}
}
XimIC::~XimIC()
{
if (g_option_mask & OPT_TRACE) {
printf("imid=%d, icid=%d ic deleted.\n",mIMid ,mICid);
}
unset_focus();
if (current_ic == this) {
current_ic = 0;
}
//この順序は重要
delete m_kkContext;
if (mConvdisp) {
delete mConvdisp;
}
}
bool XimIC::isActive()
{
return mIsActive;
}
int XimIC::get_icid()
{
return mICid;
}
int XimIC::get_imid()
{
return mIMid;
}
void XimIC::set_focus()
{
if (mIsActive) {
return ;
}
current_ic = this;
mIsActive = true;
nrActiveIC ++;
ui_update_ic_stat();
ui_update_input_mode(m_kkContext->getMode());
if (mConvdisp) {
mConvdisp->set_focus();
}
}
void XimIC::unset_focus()
{
if (!mIsActive) {
return ;
}
mIsActive = false;
nrActiveIC --;
if (current_ic == this) {
ui_update_ic_stat();
}
if (mConvdisp) {
mConvdisp->unset_focus();
}
}
void XimIC::OnKeyEvent(keyEventX e)
{
int s,t = 0;
keyState k(&e);
if (k.is_modifier()) {
return ;
}
jstring_t *c= new jstring_t();
do {
s = m_kkContext->pushKey(&k);
t |= s;
if (s & COMMIT_RAW) {
send_key_event(&e.ev.xkey);
}
if (s & COMMIT_WIDE) {
cchar ac;
ac = ascii_to_wide(k.char_code());
if (ac) {
c->push_back(ac);
} else {
send_key_event(&e.ev.xkey);
}
}
} while(s & PUSHKEY_AGAIN);
if (t & UPDATE_MODE) {
int mode = m_kkContext->getMode();
ui_update_input_mode(mode);
}
if (t & COMMIT_WIDE) {
commit_jstring(c);
}
delete c;
}
void XimIC::changeMode(int s)
{
m_kkContext->setMode(s);
ui_update_input_mode(m_kkContext->getMode());
}
void XimIC::send_key_event(XKeyEvent *e)
{
TxPacket *t;
t = createTxPacket(XIM_FORWARD_EVENT,0);
t->pushC16(mIMid);
t->pushC16(mICid);
t->pushC16(1); //flag , synchronous
t->pushC16((e->serial>>16)&0xffff);
t->pushC8(e->type);
t->pushC8(e->keycode);
t->pushC16(e->serial &0xffff);
t->pushC32(e->time);
t->pushC32(e->root);
t->pushC32(e->window);
t->pushC32(e->subwindow);
t->pushC16(e->x_root);
t->pushC16(e->y_root);
t->pushC16(e->x);
t->pushC16(e->y);
t->pushC16(e->state);
t->pushC8(e->same_screen);
t->pushC8(0);
m_conn->push_packet(t);
}
void XimIC::commit_jstring(jstring_t *s)
{
append_jstring(&mPending, s);
}
void XimIC::extra_input(jstring_t *s)
{
if (!m_kkContext->extra_input(s)) {
commit_jstring(s);
}
if (m_xatr.has_atr(ICA_FocusWindow)) {
force_event(m_xatr.focus_window);
}
}
void XimIC::set_ic_attrs(void *val, int len)
{
unsigned char *p=(unsigned char *)val;
int byte_order = m_conn->byte_order();
int i;
for (i = 0; i < len ;) {
int atr_id, atr_len;
atr_id = readC16(&p[i], byte_order);
i += 2;
atr_len = readC16(&p[i], byte_order);
i += 2;
unsigned char *q;
q = (unsigned char *)alloca(atr_len+pad4(atr_len));
int j;
for(j = 0; j < atr_len +pad4(atr_len); j++, i++) {
q[j] = p[i];
}
set_ic_attr(atr_id, (C8 *)q, atr_len);
}
}
int XimIC::get_ic_atr(int id, TxPacket *t)
{
int l = m_xatr.getSize(id);
if (!t) {
return l;
}
switch (id) {
case ICA_FocusWindow:
t->pushC32(m_xatr.focus_window);
break;
case ICA_FilterEvents:
t->pushC32(KeyPressMask);
break;
default:
printf("try to get unknown ic attribute %d.\n",id);
break;
}
return l;
}
int XimIC::lookup_style(unsigned long s)
{
int i;
for (i = 0; input_style_tab[i].x_style; i++) {
if (input_style_tab[i].x_style == (int)s) {
return input_style_tab[i].style;
}
}
return IS_INVALID;
}
void XimIC::set_ic_attr(int id,C8 *val, int len)
{
if (id == ICA_PreeditAttribute || id == ICA_StatusAttributes) {
// attributeリスト
set_ic_attrs(val, len);
} else {
m_xatr.set_atr(id, val, len, m_conn->byte_order());
}
if (mConvdisp) {
mConvdisp->update_icxatr();
}
if (!mConvdisp && m_xatr.has_atr(ICA_InputStyle)) {
mConvdisp = create_convdisp(
lookup_style(m_xatr.input_style), m_kkContext, &m_xatr, m_conn);
if (!mConvdisp && id == ICA_InputStyle) {
show_issue(invalid_style_msg);
}
}
m_kkContext->set_convdisp(mConvdisp);
if (mConvdisp) {
mConvdisp->update_icxatr();
}
}
void XimIC::reset_ic()
{
TxPacket *t;
t = createTxPacket(XIM_RESET_IC_REPLY,0);
t->pushC16(mIMid);
t->pushC16(mICid);
jstring_t *s;
s = m_kkContext->clear();
if (s) {
char *p;
int i,len;
p = jstring_to_ctext(s);
len = strlen(p);
t->pushC16(len);
for (i = 0 ; i < len; i++) {
t->pushC8(p[i]);
}
len = pad4(len+2);
for (i = 0; i < len; i++) {
t->pushC8(p[i]);
}
free(p);
delete s;
}else{
t->pushC16(0);//コミットする文字の長さ
// ここでコミットする文字を入れる。
t->pushC16(0);//padding ( 2bytes)
}
m_conn->push_packet(t);
}
Convdisp *XimIC::get_convdisp()
{
return mConvdisp;
}
void XimIC::onSendPacket()
{
if (!mPending.size()) {
return;
}
char *p;
p = jstring_to_ctext(&mPending);
TxPacket *t;
t = createTxPacket(XIM_COMMIT, 0);
t->pushC16(mIMid);
t->pushC16(mICid);
t->pushC16(3); //XLookupChars|同期
int i,len;
len = strlen(p);
t->pushC16(len);
for (i = 0 ; i < len ; i++) {
t->pushC8(p[i]);
}
len = pad4(len);
for (i = 0 ; i < len ; i++) {
t->pushC8(0);
}
free(p);
m_conn->push_passive_packet(t);
erase_jstring(&mPending);
}
XimIC *XimIC::get_current_ic()
{
return current_ic;
}
bool XimIC::isAnyActive()
{
if ( nrActiveIC ){
return true;
}
return false;
}
XimIC *create_ic(Connection *c,RxPacket *p,int imid,int icid)
{
XimIC *ic;
ic = new XimIC(c,imid,icid);
p->rewind();
p->getC16();//discard
int atr_len = p->getC16();
unsigned char *v;
v = (unsigned char *)alloca(atr_len);
int i;
for ( i = 0 ; i < atr_len ;i++){
v[i] = p->getC8();
}
ic->set_ic_attrs((void *)v,atr_len);
if ( !ic->get_convdisp()){
delete ic;
return 0;
}
return ic;
}
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1