// XIM プロトコルで定義されるIMの処理を行う。
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <map>
#include "xim.h"
#include <X11/Xutil.h>
#define NEED_EVENTS // xEventの宣言のため、
#include <X11/Xproto.h>
#ifndef __GNUC__
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# endif
#endif
static std::map<int,XimIM *> g_ims;
class XimIM_impl : public XimIM {
public:
XimIM_impl(Connection *c,int id);
virtual ~XimIM_impl();
void create_ic(RxPacket *);
void destroy_ic(int );
void set_ic_focus(int icid);
void set_ic_values(RxPacket *, int icid);
void get_ic_values(RxPacket *);
void unset_ic_focus(int icid);
void forward_event(RxPacket *);
XimIC *get_ic_by_id(int id);
void onSendPacket();
private:
int unused_ic_id();
void free_all_ic();
void delete_ic(XimIC *);
std::map<int,XimIC *> m_ics;
};
XimIM_impl::XimIM_impl(Connection *c,int id) : XimIM(c,id)
{
}
XimIM_impl::~XimIM_impl()
{
if (g_option_mask & OPT_TRACE) {
printf("imid=%d im deleted.\n", mID);
}
free_all_ic();
}
void XimIM_impl::create_ic(RxPacket *p)
{
XimIC *ic;
int icid= unused_ic_id();
ic = ::create_ic(mConn,p,mID,icid);
if (!ic) {
mConn->push_error_packet(mID,icid,
ERR_Style,"invalid im style");
mConn->terminate();
return ;
}
std::pair<int,XimIC *> n(ic->get_icid(),ic);
m_ics.insert(n);
TxPacket *t;
t = createTxPacket(XIM_CREATE_IC_REPLY,0);
t->pushC16(mID);
t->pushC16(ic->get_icid());
mConn->push_packet(t);
}
void XimIM_impl::destroy_ic(int icid)
{
//ICを破壊
XimIC *ic = get_ic_by_id(icid);
delete_ic(ic);
}
void XimIM_impl::set_ic_values(RxPacket *p, int icid)
{
// imid, icid
p->rewind();
(void)p->getC16();
(void)p->getC16();
XimIC *ic = get_ic_by_id(icid);
int atr_len;
atr_len = p->getC16();
p->getC16();
unsigned char *v;
v = (unsigned char *)alloca(atr_len);
int i;
for ( i = 0 ; i < atr_len ; i++){
v[i] = p->getC8();
}
if (ic) {
ic->set_ic_attrs((void *)v, atr_len);
}
}
void XimIM_impl::get_ic_values(RxPacket *p)
{
int icid;
XimIC *ic;
p->rewind();
p->getC16();
icid = p->getC16();
ic = get_ic_by_id(icid);
int len;
len = p->getC16();
TxPacket *t = createTxPacket(XIM_GET_IC_VALUES_REPLY,0);
t->pushC16(mID);
t->pushC16(icid);
int i,id,l;
l = 0;
for (i = 0; i < len /2 ; i++) {
id = p->getC16();
l += ic->get_ic_atr(id, 0);
l += 4;
}
t->pushC16(l);
t->pushC16(0);
p->rewind();
p->getC16();//imid
p->getC16();//icid
p->getC16();// n
for (i = 0; i < len /2 ; i++) {
id = p->getC16();
t->pushC16(id);
t->pushC16(ic->get_ic_atr(id, 0));
l += ic->get_ic_atr(id, t);
}
mConn->push_packet(t);
}
int XimIM_impl::unused_ic_id()
{
std::map<int,XimIC *>::iterator i;
int max_id=1; // input-context IDは1から使う?
for (i = m_ics.begin(); i != m_ics.end(); i++) {
if (max_id <= (*i).first) {
max_id = (*i).first+1;
}
}
return max_id;
}
void XimIM_impl::set_ic_focus(int icid)
{
XimIC *ic = get_ic_by_id(icid);
if (ic) {
ic->set_focus();
}
}
void XimIM_impl::unset_ic_focus(int icid)
{
XimIC *ic = get_ic_by_id(icid);
if (ic) {
ic->unset_focus();
}
}
XimIC *XimIM_impl::get_ic_by_id(int icid)
{
std::map<int,XimIC *>::iterator it;
it = m_ics.find(icid);
if (it == m_ics.end()) {
return 0;
}
return it->second;
}
void XimIM_impl::forward_event(RxPacket *p)
{
unsigned char *c;
int i;
keyEventX k;
xEvent ev_raw;
int imid,icid,flag;
XimIC *ic;
imid = p->getC16();
icid = p->getC16();
flag = p->getC16();
ic = get_ic_by_id(icid);
k.serial = p->getC16();
//xEventのコピーを取る。
c = (unsigned char *)&ev_raw;
for (i = 0 ; i < (int)sizeof(ev_raw); i++) {
*c = p->getC8();
c++;
}
k.ev.type = ev_raw.u.u.type &0x7f;
k.ev.xany.serial = (k.serial << 16)| ev_raw.u.u.sequenceNumber;
k.ev.xany.display = gDpy;
k.ev.xany.send_event = ev_raw.u.u.type>127;
switch (k.ev.type) {
case KeyPress:
//case KeyRelease:
k.ev.xkey.window =
mConn->to_hl(ev_raw.u.keyButtonPointer.event);
k.ev.xkey.root =
mConn->to_hl(ev_raw.u.keyButtonPointer.root);
k.ev.xkey.subwindow =
mConn->to_hl(ev_raw.u.keyButtonPointer.child);
k.ev.xkey.time =
mConn->to_hs(ev_raw.u.keyButtonPointer.time);
k.ev.xkey.x =
mConn->to_hl(ev_raw.u.keyButtonPointer.eventX);
k.ev.xkey.y =
mConn->to_hs(ev_raw.u.keyButtonPointer.eventY);
k.ev.xkey.x_root =
mConn->to_hs(ev_raw.u.keyButtonPointer.rootX);
k.ev.xkey.y_root =
mConn->to_hs(ev_raw.u.keyButtonPointer.rootY);
k.ev.xkey.state = ev_raw.u.keyButtonPointer.state;
k.ev.xkey.keycode = ev_raw.u.u.detail;
k.ev.xkey.same_screen = ev_raw.u.keyButtonPointer.sameScreen;
char buf[10];
KeySym ks;
XLookupString(&k.ev.xkey,buf,10,&ks,0);
k.state = mConn->to_hs(ev_raw.u.keyButtonPointer.state);
k.press = (k.ev.type == KeyPress);
k.key_sym = ks;
if (ic) {
ic->OnKeyEvent(k);
}
break;
default:
printf("unknown type of forwarded event.(%d)\n", k.ev.type);
break;
}
}
void XimIM_impl::free_all_ic()
{
std::map<int,XimIC *>::iterator i;
for ( i = m_ics.begin() ; i!= m_ics.end() ; i++){
(*i).second->unset_focus();
delete (*i).second;
}
m_ics.erase(m_ics.begin(),m_ics.end());
}
void XimIM_impl::delete_ic(XimIC *ic)
{
std::map<int,XimIC *>::iterator it;
for (it = m_ics.begin(); it != m_ics.end(); it++) {
if (it->second == ic) {
it->second->unset_focus();
delete it->second;
m_ics.erase(it);
return ;
}
}
}
void XimIM_impl::onSendPacket()
{
std::map<int,XimIC *>::iterator i;
for ( i = m_ics.begin() ; i!= m_ics.end() ; i++){
(*i).second->onSendPacket();
}
}
XimIM::XimIM(Connection *c,int id)
{
mConn = c;
mID = id;
}
int unused_im_id()
{
int max_id;
std::map<int,XimIM *>::iterator i;
max_id = 1;
for ( i = g_ims.begin() ; i != g_ims.end() ; i++){
if ( (*i).first == max_id ){
max_id = (*i).first +1;
}
}
return max_id;
}
XimIM *create_im(Connection *c,int id)
{
XimIM *im;
im = new XimIM_impl(c,id);
std::pair<int , XimIM *> p(id,im);
g_ims.insert(p);
return im;
}
XimIM *get_im_by_id(int id)
{
std::map<int,XimIM *>::iterator it;
it = g_ims.find(id);
if (it == g_ims.end()) {
return NULL;
}
return it->second;
}
void close_im(int id)
{
XimIM *im;
im = get_im_by_id(id);
if (im) {
delete im;
}
std::map<int,XimIM *>::iterator it;
it = g_ims.find(id);
if (it != g_ims.end()) {
g_ims.erase(it);
}
}
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1