// classes for preedit draw
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>
#include <stdlib.h>
#include "xim.h"
#include "kkconv.h"
#include "convdisp.h"
#include "xdispatch.h"
#include "gtkdispatch.h"
#define INVALID_POS -1
//
// PeWinプリエディット用の基本ウィンドウ
// PeLineWin root window style
// PeOvWin over the spot
// CandidateWin 候補表示用のウィンドウ
//IMEはインタラクティブである必要があるので、気安くXFlushを使う。
static XFontSet gFontset;
void init_convdisp()
{
char **missing, *def;
int nr_missing;
gFontset =
XCreateFontSet(gDpy,
"-misc-fixed-medium-r-normal--14-110-100-100-c-70-iso8859-1,"
"-misc-fixed-medium-r-normal--14-130-75-75-c-140-jisx0208.1983-0,"
"-misc-fixed-medium-r-normal--14-130-75-75-c-70-jisx0201.1976-0",
&missing, &nr_missing, &def);
// ktermの使うフォントセットを取ってきた。
if (missing) {
XFreeStringList(missing);
}
}
struct char_ent {
cchar c;
int stat;
int width;
int height;
int x, y;
};
// プリエディットWindow
class PeWin : public WindowIf {
public:
PeWin(Window pw);
virtual ~PeWin();
virtual void release();
virtual void destroy(Window);
void expose(Window w);
void draw_char(int x,int y,cchar ch,int stat);
void set_back(unsigned long p);
void set_fore(unsigned long p);
void set_fontset(XFontSet f);
virtual void set_size(int w,int h);
void set_pos(int x,int y);
void do_map();
void clear();
void draw();
void unmap();
protected:
Window mParentWin;
Window mWin;
Pixmap mPixmap;
GC mGC,mClearGC;
GC mHilitGC;
unsigned int mFore,mBack;
XFontSet mFontset;
int mWidth,mHeight;
bool mIsMapped;
};
// RootWindowStyle用の1行ウィンドウ
class PeLineWin : public PeWin {
public:
PeLineWin(Window w);
virtual ~PeLineWin();
void draw_pe(pe_stat *p);
void draw_segment(pe_jstring *s);
private:
void calc_extent(pe_stat *p);
int m_x;
};
// over the spot用のウィンドウ
class PeOvWin : public PeWin {
public:
PeOvWin(Window w);
void draw_ce(char_ent *ce,int len);
virtual void set_size(int w,int h);
virtual ~PeOvWin();
private:
void draw_a_ce(char_ent *ce);
Pixmap m_mask_pix;
GC m_mask_pix_gc;
};
//
//候補表示用のウィンドウ
// ConvdispOvの作成時と破棄時にそれぞれ作成、破棄される
//
class CandidateWin : WidgetIf{
public:
CandidateWin(Convdisp *);
virtual ~CandidateWin();
void update(pe_stat *);
virtual void select_row(GtkWidget *,int,int );
virtual void key_press(GtkWidget *w,GdkEventKey *e);
void set_pos(int x, int y);
void show();
void hide();
private:
void build_candidate_list();
bool trim_base_row();
GtkWidget *top_win;
GtkWidget *clist;
Convdisp *mConvdisp;
pe_stat *m_pe;
bool bInit;
int m_select_count;
int m_base_row;
};
class ConvdispOv : public Convdisp{
public:
ConvdispOv(KKContext *,icxatr *);
virtual ~ConvdispOv();
void update_preedit();
virtual void update_icxatr();
virtual void set_focus();
virtual void unset_focus();
private:
bool check_win();
bool check_atr();
void layoutCharEnt();
void make_ce_array();
void drawPreedit();
void do_draw_preedit();
int calc_ce_width(int b,int e);
void validate_area();
char_ent *m_ce;
int m_ce_len;
PeOvWin *m_ov_win;
};
// RootWindowスタイル
class ConvdispRw : public Convdisp{
public:
ConvdispRw(KKContext *,icxatr *);
virtual ~ConvdispRw();
void update_preedit();
virtual void update_icxatr();
private:
PeLineWin *mPeWin;
};
class Connection;
class ConvdispOs : public Convdisp{
public:
ConvdispOs(KKContext *,icxatr *,Connection *);
virtual ~ConvdispOs();
virtual void update_preedit();
virtual void update_icxatr();
virtual void set_focus();
virtual void unset_focus();
private:
void compose_preedit_array(TxPacket *);
void compose_feedback_array(TxPacket *);
void update_CandidateWin();
Connection *mConn;
int mImid,mIcid;
int mPrevLen;
};
CandidateWin *g_cur_cand_win;
Convdisp *create_convdisp(int style, KKContext *k,
icxatr *a, Connection *c)
{
switch (style) {
case IS_ROOT_WINDOW:
return new ConvdispRw(k, a);
case IS_OVER_THE_SPOT:
return new ConvdispOv(k, a);
case IS_ON_THE_SPOT:
return new ConvdispOs(k, a, c);
default:
break;
}
return 0;
}
//
// PeWin(PreeEdit Window)
//
PeWin::PeWin(Window pw)
{
mParentWin = pw;
int scr_num = DefaultScreen(gDpy);
// とりあえずテキトー
mWidth = 1;
mHeight = 1;
mWin = XCreateSimpleWindow(gDpy, mParentWin,
0, 0, mWidth, mHeight, 0,
BlackPixel(gDpy, scr_num),
WhitePixel(gDpy, scr_num));
XSetWindowAttributes attr;
attr.override_redirect = True;
XChangeWindowAttributes(gDpy, mWin, CWOverrideRedirect,
&attr);
mPixmap = XCreatePixmap(gDpy, DefaultRootWindow(gDpy),
mWidth, mHeight,
DefaultDepth(gDpy, scr_num));
mGC = XCreateGC(gDpy, mPixmap, 0, 0);
mClearGC = XCreateGC(gDpy, mPixmap, 0, 0);
mHilitGC = XCreateGC(gDpy, mPixmap, 0, 0);
XSetBackground(gDpy, mGC, WhitePixel(gDpy, scr_num));
XSetForeground(gDpy, mGC, BlackPixel(gDpy, scr_num));
XSetForeground(gDpy, mClearGC, WhitePixel(gDpy, scr_num));
XSetBackground(gDpy, mClearGC, BlackPixel(gDpy, scr_num));
add_window_watch(mWin, this, EXPOSE_MASK|STRUCTURE_NOTIFY_MASK);
mIsMapped = false;//マップされてない
mFontset = gFontset;
XFlush(gDpy);
}
PeWin::~PeWin()
{
if (mWin) {
release();
}
XFreePixmap(gDpy, mPixmap);
XFreeGC(gDpy, mGC);
XFreeGC(gDpy, mClearGC);
XFreeGC(gDpy, mHilitGC);
XFlush(gDpy);
}
void PeWin::release()
{
remove_window_watch(mWin);
XDestroyWindow(gDpy, mWin);
mWin = 0;
}
void PeWin::destroy(Window w)
{
if (mWin && mWin == w) {
mWin = 0;
}
}
void PeWin::expose(Window w)
{
XCopyArea(gDpy, mPixmap, mWin, mGC,
0, 0, mWidth, mHeight, 0, 0);
XFlush(gDpy);
}
void PeWin::draw_char(int x,int y,cchar ch,int stat)
{
GC gc = mGC;
if (stat & PE_REVERSE) {
gc = mClearGC;
}
if (stat & PE_HILIGHT) {
//gc = mHilitGC;
}
if (ch < 256) {
char c = ch;
XmbDrawImageString(gDpy, mPixmap, mFontset, gc, x, y, &c, 1);
} else {
unsigned char c[2];
c[0] = ((ch >>8)&255)|0x80;
c[1] = (ch & 255)|0x80;
XmbDrawImageString(gDpy, mPixmap, mFontset,
gc, x, y, (char *)c, 2);
}
}
void PeWin::set_back(unsigned long p)
{
mBack = p;
XSetBackground(gDpy, mGC, p);
XSetForeground(gDpy, mClearGC, p);
}
void PeWin::set_fore(unsigned long p)
{
mFore = p;
XSetForeground(gDpy, mGC, p);
XSetBackground(gDpy, mClearGC, p);
}
void PeWin::set_fontset(XFontSet f)
{
mFontset = f;
}
void PeWin::set_size(int w, int h)
{
if (w == mWidth && h == mHeight) {
return ;
}
XResizeWindow(gDpy, mWin, w, h);
XFreePixmap(gDpy, mPixmap);
mPixmap =XCreatePixmap(gDpy, DefaultRootWindow(gDpy), w, h,
DefaultDepth(gDpy, DefaultScreen(gDpy)));
mWidth = w;
mHeight = h;
clear();
}
void PeWin::set_pos(int x, int y)
{
XWindowChanges ch;
ch.x = x;
ch.y = y;
XConfigureWindow(gDpy, mWin, CWX|CWY, &ch);
}
void PeWin::do_map()
{
if (!mIsMapped) {
XFlush(gDpy);
XMapRaised(gDpy, mWin);
mIsMapped = true;
}
}
void PeWin::clear()
{
XFillRectangle(gDpy, mPixmap, mClearGC,
0, 0, mWidth, mHeight);
}
void PeWin::draw()
{
if (!mIsMapped) {
do_map();
} else {
expose(mWin);
}
}
void PeWin::unmap()
{
if (mIsMapped) {
XUnmapWindow(gDpy, mWin);
XFlush(gDpy);
mIsMapped = false;
}
}
//
// PeLineWin
//
PeLineWin::PeLineWin(Window w) : PeWin(w)
{
set_size(400, 40);
clear();
}
PeLineWin::~PeLineWin()
{
}
void PeLineWin::draw_pe(pe_stat *p)
{
clear();
calc_extent(p);
m_x = 0;
std::list<pe_jstring>::iterator i;
for (i = p->jstrings.begin(); i != p->jstrings.end(); i++) {
draw_segment(&(*i));
}
}
void PeLineWin::draw_segment(pe_jstring *s)
{
jstring_t::iterator i;
for (i = s->s.begin(); i != s->s.end(); i++) {
cchar ch= *i;
draw_char(m_x, 20, ch, s->stat);
m_x += 20;
}
}
void PeLineWin::calc_extent(pe_stat *p)
{
int c;
c = p->get_char_count();
set_size(400, 40);
}
//
// PeOvWin
//
PeOvWin::PeOvWin(Window w) : PeWin(w)
{
m_mask_pix = 0;
m_mask_pix_gc = 0;
}
PeOvWin::~PeOvWin()
{
if (m_mask_pix) {
XFreePixmap(gDpy, m_mask_pix);
XFreeGC(gDpy, m_mask_pix_gc);
}
}
void PeOvWin::set_size(int w, int h)
{
if (w == mWidth && h == mHeight) {
return ;
}
PeWin::set_size(w, h);
if (m_mask_pix) {
XFreePixmap(gDpy, m_mask_pix);
m_mask_pix = XCreatePixmap(gDpy, mWin,
mWidth, mHeight, 1);
}
}
void PeOvWin::draw_ce(char_ent *ce, int len)
{
if (m_mask_pix == 0) {
m_mask_pix = XCreatePixmap(gDpy, mWin, mWidth, mHeight, 1);
m_mask_pix_gc = XCreateGC(gDpy, m_mask_pix, 0, 0);
}
clear();
XSetForeground(gDpy, m_mask_pix_gc, BlackPixel(gDpy, DefaultScreen(gDpy)));
XFillRectangle(gDpy, m_mask_pix, m_mask_pix_gc, 0, 0, mWidth, mHeight);
XSetForeground(gDpy, m_mask_pix_gc, WhitePixel(gDpy, DefaultScreen(gDpy)));
int i;
for (i = 0; i < len; i++) {
draw_a_ce(&ce[i]);
}
XShapeCombineMask(gDpy, mWin, ShapeBounding,
0, 0, m_mask_pix, ShapeSet);
do_map();
}
void PeOvWin::draw_a_ce(char_ent *ce)
{
draw_char(ce->x, ce->y, ce->c, ce->stat);
XFillRectangle(gDpy, m_mask_pix, m_mask_pix_gc,
ce->x, ce->y - ce->height + 2,
ce->width, ce->height+1);
if (ce->stat & PE_UNDERLINE) {
XDrawLine(gDpy, mPixmap, mGC, ce->x, ce->y+2,
ce->x+ce->width, ce->y + 2);
}
}
//
//
//
CandidateWin::CandidateWin(Convdisp *c)
{
mConvdisp = c;
gchar *titles[2]={"index","候補"};
bInit = false;
m_pe = 0;
top_win = gtk_window_new(GTK_WINDOW_POPUP);
gtk_widget_set_usize(top_win, CAND_WIN_WIDTH, CAND_WIN_HEIGHT);
clist = gtk_clist_new_with_titles(2, titles);
gtk_container_add(GTK_CONTAINER(top_win), clist);
gtk_clist_set_column_width(GTK_CLIST(clist), 0, 50);
gtk_clist_set_column_width(GTK_CLIST(clist), 1, 150);
gtk_widget_show(clist);
add_widget_watch(clist, WIDGET_ROW_SELECTED, this);
add_widget_watch(top_win, WIDGET_KEY_PRESS, this);
m_select_count = 0;
}
CandidateWin::~CandidateWin()
{
if (g_cur_cand_win == this) {
g_cur_cand_win = 0;
}
gtk_widget_destroy(top_win);
}
void CandidateWin::select_row(GtkWidget *w, int row, int col)
{
if (m_select_count == 0) {
m_pe->cands->nth = row;
mConvdisp->candidate_selected(row);
}else{
m_select_count --;
}
}
void CandidateWin::key_press(GtkWidget *w, GdkEventKey *e)
{
keyState k(e);
if (k.is_modifier()) {
return ;
}
m_pe->cont->pushKey(&k);
}
void CandidateWin::set_pos(int x, int y)
{
if (x == INVALID_POS) {
x = (gdk_screen_width() - CAND_WIN_WIDTH) / 2;
}
if (y == INVALID_POS) {
y = gdk_screen_height() - CAND_WIN_HEIGHT;
}
gtk_widget_set_uposition(top_win, x, y);
}
void CandidateWin::update(pe_stat *pe)
{
m_pe = pe;
if (pe->cands) {
int nth = m_pe->cands->nth;
if (!bInit) {
m_base_row = 0;
bInit = true;
build_candidate_list();
m_select_count = 1;
}
if (trim_base_row()) {
build_candidate_list();
m_select_count = 1;
}
show();
gtk_clist_select_row((GtkCList*)clist, nth-m_base_row, 0);
m_select_count ++;
} else {
bInit = false;
gtk_widget_hide(top_win);
gtk_clist_clear((GtkCList*)clist);
}
}
bool CandidateWin::trim_base_row()
{
int nth = m_pe->cands->nth;
if (m_base_row +CAND_COUNT > nth && m_base_row <= nth) {
return false;
}
while (m_base_row +CAND_COUNT <= nth) {
m_base_row += CAND_COUNT;
}
while (m_base_row > nth) {
m_base_row -=CAND_COUNT;
}
return true;
}
void CandidateWin::build_candidate_list()
{
int i;
int size = m_pe->cands->cands.size();
char idx[12];
char *buf[2];
gtk_clist_clear((GtkCList*)clist);
for (i = m_base_row; i < (int)size && i < m_base_row + CAND_COUNT; i++) {
char *c;
if (i == m_base_row && i > 0) {
sprintf(idx,"%d(<<)",i+1);
} else if (i == m_base_row + CAND_COUNT - 1 && i < size) {
sprintf(idx,"%d(>>)", i+1);
} else {
sprintf(idx,"%d", i+1);
}
c = jstring_to_str(&m_pe->cands->cands[i]);
buf[0]= idx;
buf[1] = c;
gtk_clist_append((GtkCList*)clist, buf);
free(c);
}
sprintf(idx, "(%d/%d)", m_base_row, size);
buf[0] = "候補数";
buf[1] = idx;
gtk_clist_append((GtkCList*)clist, buf);
}
void CandidateWin::show()
{
if (m_pe && m_pe->cands && bInit) {
if (g_cur_cand_win && g_cur_cand_win !=this) {
g_cur_cand_win->hide();
}
g_cur_cand_win = this;
gtk_widget_show(top_win);
}
}
void CandidateWin::hide()
{
gtk_widget_hide(top_win);
}
//
//
//
Convdisp::Convdisp(KKContext *k, icxatr *a)
{
mKkContext = k;
m_atr = a;
m_cands_win = new CandidateWin(this);
}
Convdisp::~Convdisp()
{
delete m_cands_win;
}
void Convdisp::set_pe(pe_stat *p)
{
m_pe = p;
}
void Convdisp::candidate_selected(int n)
{
if (n == 12) {
return ;
}
mKkContext->candidate_selected(n);
}
//ルートウィンドウスタイル
ConvdispRw::ConvdispRw(KKContext *k, icxatr *a) : Convdisp(k, a)
{
mPeWin = new PeLineWin(DefaultRootWindow(gDpy));
}
ConvdispRw::~ConvdispRw()
{
delete mPeWin;
}
void ConvdispRw::update_preedit()
{
if (m_pe && m_pe->get_char_count()) {
// preeditの中身が存在すれば
mPeWin->do_map();
mPeWin->draw_pe(m_pe);
mPeWin->draw();
} else {
mPeWin->clear();
mPeWin->expose(0);
XFlush(gDpy);
}
m_cands_win->set_pos(0, 0);
m_cands_win->update(m_pe);
}
void ConvdispRw::update_icxatr()
{
}
//Over the spot style
ConvdispOv::ConvdispOv(KKContext *k, icxatr *a) : Convdisp(k, a)
{
m_ov_win = 0;
}
ConvdispOv::~ConvdispOv()
{
if (m_ov_win) {
delete m_ov_win;
}
}
void ConvdispOv::update_preedit()
{
if (!m_pe) {
return ;
}
if (!m_pe->get_char_count()) {
delete m_ov_win;
m_ov_win = NULL;
m_cands_win->update(m_pe);
return ;
}
// preeditを書く
drawPreedit();
// update candidate window
if (m_atr->has_atr(ICA_FocusWindow)
&& m_atr->has_atr(ICA_SpotLocation)){
int x, y;
Window win;
XTranslateCoordinates(gDpy,m_atr->focus_window,
DefaultRootWindow(gDpy),
m_atr->spot_location.x,
m_atr->spot_location.y,
&x, &y, &win);
if (x + CAND_WIN_WIDTH > scr_width) {
x = scr_width - CAND_WIN_WIDTH;
}
if (x < 0) {
x = 0;
}
if (y + CAND_WIN_HEIGHT > scr_height) {
//上側に候補ウィンドウを出す。
y -= (CAND_WIN_HEIGHT+m_atr->line_space+2);
}else{
// 下側に候補ウィンドウを出す。
y += 2;
}
m_cands_win->set_pos(x, y);
}else{
m_cands_win->set_pos(INVALID_POS, INVALID_POS);
}
m_cands_win->update(m_pe);
}
void ConvdispOv::validate_area()
{
Window r, win;
int x;
unsigned int w, h, tmp;
if (m_atr->has_atr(ICA_ClientWindow)) {
win = m_atr->client_window;
} else {
win = m_atr->focus_window;
}
XGetGeometry(gDpy, win,
&r, &x, &x, &w, &h, &tmp, &tmp);
/* そんな無茶な,, (RedHat7.3のQt対策、たぶん他のQtもこの動作)*/
m_atr->area.width = w;
m_atr->area.height = h;
}
void ConvdispOv::update_icxatr()
{
if (!m_ov_win) {
return ;
}
if (m_atr->is_changed(ICA_FocusWindow)) {
//なんか忘れたけど、FocusWindowを後から指定してくるものがある
if (!check_win()) {
return ;
}
}
if (m_atr->is_changed(ICA_Area)) {
if (m_atr->area.width == 0) {
validate_area();
}
m_ov_win->set_size(m_atr->area.width, m_atr->area.height);
m_atr->unset_change_mask(ICA_Area);
}
if (m_atr->is_changed(ICA_Foreground)) {
m_ov_win->set_fore(m_atr->foreground_pixel);
m_atr->unset_change_mask(ICA_Foreground);
}
if (m_atr->is_changed(ICA_Background)) {
m_ov_win->set_back(m_atr->background_pixel);
m_atr->unset_change_mask(ICA_Background);
}
if (m_atr->is_changed(ICA_FontSet)) {
m_ov_win->set_fontset(m_atr->font_set);
m_atr->unset_change_mask(ICA_FontSet);
}
update_preedit();
}
void ConvdispOv::set_focus()
{
m_cands_win->show();
}
void ConvdispOv::unset_focus()
{
}
void ConvdispOv::drawPreedit()
{
m_ce_len = m_pe->get_char_count();
if (!check_win()) {
return ;
}
m_ce = (char_ent *)malloc(sizeof(char_ent)*m_ce_len);
make_ce_array();//配列を準備して、
layoutCharEnt();//レイアウトして、
do_draw_preedit();//描画
free(m_ce);
m_cands_win->update(m_pe);
m_ov_win->draw();
XFlush(gDpy);
}
void ConvdispOv::do_draw_preedit()
{
m_ov_win->set_pos(0, 0);
m_ov_win->draw_ce(m_ce, m_ce_len);
}
bool ConvdispOv::check_win()
{
if (!check_atr()) {
//プリエディットウィンドウを出すのに十分な情報が無い。
return false;
}
if (m_ov_win && !m_atr->is_changed(ICA_FocusWindow)) {
// ウィンドウをupdateする必要は無い。
return true;
}
if (m_ov_win) {
delete m_ov_win;
}
m_atr->unset_change_mask(ICA_FocusWindow);
m_atr->unset_change_mask(ICA_Foreground);
m_atr->unset_change_mask(ICA_Background);
m_atr->unset_change_mask(ICA_FontSet);
Window w;
if (m_atr->has_atr(ICA_ClientWindow)) {
w = m_atr->client_window;
} else {
w = m_atr->focus_window;
}
m_ov_win = new PeOvWin(w);
m_ov_win->set_size(m_atr->area.width, m_atr->area.height);
m_ov_win->set_fore(m_atr->foreground_pixel);
m_ov_win->set_back(m_atr->background_pixel);
m_ov_win->set_fontset(m_atr->font_set);
return true;
}
bool ConvdispOv::check_atr()
{
if (!m_atr->has_atr(ICA_FocusWindow) &&
!m_atr->has_atr(ICA_ClientWindow)) {
return false;
}
if (!m_atr->has_atr(ICA_SpotLocation)) {
//入力場所が未定なら左上
m_atr->spot_location.x = 0;
m_atr->spot_location.y = 0;
}
if (!m_atr->has_atr(ICA_Area) ||
m_atr->area.width == 0) {
validate_area();
m_atr->area.x = 0;
m_atr->area.y = 0;
}
if (!m_atr->has_atr(ICA_FontSet)) {
m_atr->font_set = gFontset;
}
if (!m_atr->has_atr(ICA_LineSpace)) {
m_atr->line_space = 14;
}
if (!m_atr->has_atr(ICA_Foreground)) {
m_atr->foreground_pixel = BlackPixel(gDpy, DefaultScreen(gDpy));
}
if (!m_atr->has_atr(ICA_Background)) {
m_atr->background_pixel = WhitePixel(gDpy, DefaultScreen(gDpy));
}
return true;
}
void ConvdispOv::make_ce_array()
{
std::list<pe_jstring>::iterator i;
jstring_t::iterator j;
int s;
int c = 0;
for (i = m_pe->jstrings.begin(); i != m_pe->jstrings.end(); i++) {
s = (*i).stat;
for (j = (*i).s.begin(); j != (*i).s.end(); j++) {
m_ce[c].c = *j;
m_ce[c].stat = s;
c++;
}
}
}
void ConvdispOv::layoutCharEnt()
{
int i;
int x,y;
x = m_atr->spot_location.x;
y = m_atr->spot_location.y;
for (i = 0; i < m_ce_len; i++) {
cchar ch = m_ce[i].c;
char buf[2];
int l;
XRectangle ink,logical;
if (ch < 256) {
buf[0] = ch;
l = 1;
} else {
buf[1] = (ch & 255)|0x80;
buf[0] = ((ch>>8)&255)|0x80;
l = 2;
}
XmbTextExtents(m_atr->font_set, buf, l, &ink, &logical);
m_ce[i].width = logical.width;
m_ce[i].height = logical.height;
if (m_ce[i].width + x >
m_atr->area.width /*+ m_atr->area.x*/) {
x = 0;/*m_atr->area.x;*/
y += m_atr->line_space;
}
m_ce[i].x = x;
m_ce[i].y = y;
x += m_ce[i].width;
}
}
int ConvdispOv::calc_ce_width(int b, int e)
{
int i,w=0;
for (i = b; i < e; i++) {
w += m_ce[i].width;
}
return w;
}
ConvdispOs::ConvdispOs(KKContext *k, icxatr *a, Connection *c)
: Convdisp(k, a)
{
XimIC *ic=k->get_ic();
mConn = c;
mImid = ic->get_imid();
mIcid = ic->get_icid();
mPrevLen = 0;
}
ConvdispOs::~ConvdispOs()
{
}
void ConvdispOs::update_preedit()
{
if (!m_pe) {
return ;
}
update_CandidateWin();
TxPacket *t;
int len;
len = m_pe->get_char_count();
if (mPrevLen == 0 && len == 0) {
return ;
}
if (mPrevLen == 0 && len) {
t = createTxPacket(XIM_PREEDIT_START, 0);
t->pushC16(mImid);
t->pushC16(mIcid);
mConn->push_passive_packet(t);
}
t = createTxPacket(XIM_PREEDIT_DRAW, 0);
t->pushC16(mImid);
t->pushC16(mIcid);
t->pushC32(0);// caret
t->pushC32(0); // chg_first
t->pushC32(mPrevLen); // chg_length
//feedback array をセットしないとmozillaが落ちるが、それはIMEが悪いと考えるのが普通だろう。
if (m_pe->jstrings.size()) {
t->pushC32(0);
} else {
t->pushC32(3);
}
compose_preedit_array(t);
compose_feedback_array(t);
mConn->push_passive_packet(t);
if (mPrevLen && len == 0) {
t = createTxPacket(XIM_PREEDIT_DONE, 0);
t->pushC16(mImid);
t->pushC16(mIcid);
mConn->push_passive_packet(t);
}
mPrevLen = len;
/*
t = createTxPacket(XIM_PREEDIT_CARET,0);
t->pushC16(mImid);
t->pushC16(mIcid);
t->pushC32(pos);
t->pushC32(dir);
t->pushC32(style);
mConn->push_passive_packet(t);
*/
}
void ConvdispOs::update_icxatr()
{
}
void ConvdispOs::compose_preedit_array(TxPacket *t)
{
jstring_t s;
std::list<pe_jstring>::iterator it;
for (it = m_pe->jstrings.begin(); it != m_pe->jstrings.end(); it++) {
append_jstring(&s, &(*it).s);
}
char *c = jstring_to_ctext(&s);
int i,len;
len = strlen(c);
t->pushC16(len);// LENGTH
for (i = 0 ; i < len ; i++) {
t->pushC8(c[i]); // CTEXT
}
len = pad4(len+2);
for (i = 0; i < len; i++) {
t->pushC8(0); // PADDING
}
free(c);
}
void ConvdispOs::compose_feedback_array(TxPacket *t)
{
int i,len,stat,xstat;
len = m_pe->get_char_count();
t->pushC16(len*4);
t->pushC16(0);
std::list<pe_jstring>::iterator it;
for (it = m_pe->jstrings.begin(); it != m_pe->jstrings.end(); it++) {
len = (*it).s.size();
stat = (*it).stat;
xstat = FB_None;
if (stat & PE_REVERSE) {
xstat |= FB_Reverse;
}
if (stat & PE_UNDERLINE) {
xstat |= FB_Underline;
}
if (stat & PE_HILIGHT) {
xstat |= FB_Highlight;
}
for (i = 0; i < len; i++) {
t->pushC32(xstat);
}
}
}
void ConvdispOs::set_focus()
{
m_cands_win->show();
}
void ConvdispOs::unset_focus()
{
}
void ConvdispOs::update_CandidateWin()
{
m_cands_win->set_pos(INVALID_POS, INVALID_POS);
m_cands_win->update(m_pe);
}
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1