/* # skkinput (Simple Kana-Kanji Input)
 * draw.c --- Draw cursor, draw fonts, ... 
 * This file is part of skkinput.
 * Copyright (C) 1997
 * Takashi SAKAMOTO (sakamoto@yajima.kuis.kyoto-u.ac.jp)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with skkinput; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>

#include "config.h"
#include "commondef.h"
#include "buffers.h"
#include "kanji.h"
#include "draw.h"

/*
 * プロトタイプ宣言。
 */
int		myCharTextWidth (struct skkinputManagedFont**, const struct myChar*, int) ;

/*
 * グローバル変数。
 */
static char*	skkinput_ModelineStrings [NUMBER_OF_MODELINE] = {
	"SKK:", "全英", "カナ", "かな",
} ;

static const struct myChar	sstrModelineSkkMode []	= {
	{ CHARSET_ISO8859_1,		'S' },
	{ CHARSET_ISO8859_1,		'K' },
	{ CHARSET_ISO8859_1,		'K' },
	{ CHARSET_ISO8859_1,		':' },
	{ CHARSET_ISO8859_1,		'\0' },
} ;

static const struct myChar	sstrModelineZenei []	= {
	{ CHARSET_JISX0208_1983,	0x4134, /* 全 */ },
	{ CHARSET_JISX0208_1983,	0x3151, /* 英 */ },
	{ CHARSET_ISO8859_1,		'\0' },
} ;

static const struct myChar	sstrModelineKatakana []	= {
	{ CHARSET_JISX0208_1983,	0x252b, /* カ */ },
	{ CHARSET_JISX0208_1983,	0x254a, /* ナ */ },
	{ CHARSET_ISO8859_1,		'\0' },
} ;

static const struct myChar	sstrModelineKana []	= {
	{ CHARSET_JISX0208_1983,	0x242b, /* か */ },
	{ CHARSET_JISX0208_1983,	0x244a, /* な */ },
	{ CHARSET_ISO8859_1,		'\0' },
} ;

static const struct myChar*	rstrModeline [NUMBER_OF_MODELINE] = {
	sstrModelineSkkMode,	sstrModelineZenei,
	sstrModelineKatakana,	sstrModelineKana,
} ;

static const int	srnLengthModeline [NUMBER_OF_MODELINE]	= {
	sizeof (sstrModelineSkkMode)  / sizeof (sstrModelineSkkMode  [0]) - 1,
	sizeof (sstrModelineZenei)    / sizeof (sstrModelineZenei    [0]) - 1,
	sizeof (sstrModelineKatakana) / sizeof (sstrModelineKatakana [0]) - 1,
	sizeof (sstrModelineKana)     / sizeof (sstrModelineKana     [0]) - 1,
} ;

/* 辞書の修正によって違うモードライン。*/
static char*	skkinput_ModelineStringsJisyo [NUMBER_OF_MODELINE_JISYO] = {
	"-", "*", 
} ;

static char *skkinput_ModelineStringsOverTheSpot [NUMBER_OF_MODELINE_OVERTHESPOT] = {
	"*",	/* !OverSpot */
	"-",	/*  OverSpot */
} ;

/*
 * skkinput の窓の指定された場所にキャラクタを表示する関数。
 *----
 * flag は重ね合わせ処理を行うかどうか。カーソルの表示に関係する。
 * 反転表示をするかどうかは、gc で指定することになっている。
 */
int	
skkwin_jputchar (
	register Display*						disp,
	register Window							win,
	register struct skkinputManagedFont**	fontset,
	register GC								gc,
	register int							x, 
	register int							y,
	register int							chara,
	register int							flag)
{
	register XFontStruct *font ;
	XChar2b wchara ;
	char schara ;

	if (chara > 0x100 && fontset [CHARSET_JISX0208_1983] != NULL ){
		/* 文字列の表示。*/
		wchara.byte1	= (chara & 0x07F00) >> 8 ;
		wchara.byte2	= (chara & 0x0007F) ;
		font			= (fontset [CHARSET_JISX0208_1983])->font ;
		XSetFont (disp, gc, font->fid) ;
		if (flag){
			XDrawString16 (disp, win, gc, x, y, &wchara, 1) ;
		} else {
			XDrawImageString16 (disp, win, gc, x, y, &wchara, 1) ;
		}
		x += XTextWidth16( font, &wchara, 1 ) ;
	} else if (fontset [CHARSET_ASCII] != NULL){
		font	= (fontset [CHARSET_ASCII])->font ;
		XSetFont (disp, gc, font->fid) ;
		schara	= chara ;	
		if (flag){
			XDrawString( disp, win, gc, x, y, &schara, 1 ) ;
		} else {
			XDrawImageString( disp, win, gc, x, y, &schara, 1 ) ;
		}
		x += XTextWidth( font, &schara, 1 ) ;
	} else {
		x += DEFAULT_TOFU_WIDTH ;
	}
	return x ;
}

/*
 * skk window の中の文字を消去する関数。
 *----
 * x, y は座標。
 */
void skkwin_jerase (
	register Display*	disp,
	register Window		win,
	register GC			gc,
	register int		x,
	register int		y,
	register int		font_ascent,
	register int		width,
	register int		height)
{
	XFillRectangle (disp, win, gc, x, y - font_ascent, width, height) ;
	return ;
}

/*
 * skkinput の窓の指定された場所にキャラクタを表示する関数。
 *----
 * flag は重さね合わせ表示するかどうか。今一つどういう局面で利用してい
 * たのか思い出せないけど…カーソル位置での文字の表示だろうか？
 */
int
skkwin_jputMyChar (
	register Display*						disp,
	register Window							win,
	register struct skkinputManagedFont**	fontset,
	register GC								gc,
	register GC								rgc,
	register int							x,
	register int							y,
	register struct myChar					chara, 
	register int							font_height,
	register int							font_ascent,
	register int							flag)
{
	register XFontStruct*	font ;
	char					schara ;
	XChar2b					wchara ;
	register int			width ;

	if (fontset [(int)chara.charset] == NULL)
		return (x + DEFAULT_TOFU_WIDTH) ;

	font	= fontset [(int)chara.charset]->font ;
	XSetFont (disp, gc, font->fid) ;
	switch (chara.charset){
	case CHARSET_ISO8859_1 :
	case CHARSET_ISO8859_2 :
	case CHARSET_ISO8859_3 :
	case CHARSET_ISO8859_4 :
	case CHARSET_ISO8859_5 :
	case CHARSET_ISO8859_6 :
	case CHARSET_ISO8859_7 :
	case CHARSET_ISO8859_8 :
	case CHARSET_ISO8859_9 :
	case CHARSET_JISX0201_1976 :
		schara = chara.chara ;
		width = XTextWidth( font, &schara, 1 ) ;
		if (flag){
			XDrawString (disp, win, gc, x, y, &schara, 1) ;
		} else {
			skkwin_jerase
				( disp, win, rgc, x, y, font_ascent, width, font_height ) ;
			XDrawImageString( disp, win, gc, x, y, &schara, 1 ) ;
		}
		break ;
	case CHARSET_JISX0208_1978 :
	case CHARSET_JISX0208_1983 :
	case CHARSET_JISX0212_1990 :
	case CHARSET_GB2312_1980 :
	case CHARSET_KSC5601_1987 :
		wchara.byte1 = chara.chara >> 8 ;
		wchara.byte2 = chara.chara & 0x00FF ;
		width = XTextWidth16( font, &wchara, 1 ) ;
		if( flag ){
			XDrawString16( disp, win, gc, x, y, &wchara, 1 ) ;
		} else {
			skkwin_jerase
				( disp, win, rgc, x, y, font_ascent, width, font_height ) ;
			XDrawImageString16
				( disp, win, gc, x, y, &wchara, 1 ) ;
		}
		break ;
	default :
		return x ;
	}
	return ( x + width ) ;
}

/*
 * 指定されたウィンドウの指定された位置に文字列を表示する関数。
 *----
 * 自動改行はしないので、フォントの幅の情報しか渡さない。
 */
int
skkwin_jputstring (
	register Display*						disp, 
	register Window							win,
	register struct skkinputManagedFont**	fontset,
	register GC								gc,
	register int							x, 
	register int							y,
	register const struct myChar*			text )
{
	register XFontStruct*	font = NULL ;
	char			schara ;
	XChar2b			wchara ;
	register int	width ;

	for ( ; !IS_END_OF_STRING (*text) ; text ++){
		if (fontset [(int)text->charset] == NULL)
			continue ;
		if (font != fontset[ ( int )text->charset ]->font){
			/* そうそう頻繁に XSetFont したくないので、前と同じなら使わない。*/
			font = fontset[ ( int )text->charset ]->font ;
			XSetFont( disp, gc, font->fid ) ;
		}
		width = myCharTextWidth( fontset, text, 1 ) ;
		switch( text->charset ){
		case CHARSET_ISO8859_1 :
		case CHARSET_ISO8859_2 :
		case CHARSET_ISO8859_3 :
		case CHARSET_ISO8859_4 :
		case CHARSET_ISO8859_5 :
		case CHARSET_ISO8859_6 :
		case CHARSET_ISO8859_7 :
		case CHARSET_ISO8859_8 :
		case CHARSET_ISO8859_9 :
		case CHARSET_JISX0201_1976 :
			schara = text->chara ;
			XDrawString( disp, win, gc, x, y, &schara, 1 ) ;
			break ;
		case CHARSET_JISX0208_1978 :
		case CHARSET_JISX0208_1983 :
		case CHARSET_JISX0212_1990 :
		case CHARSET_GB2312_1980 :
		case CHARSET_KSC5601_1987 :
			wchara.byte1 = text->chara >> 8 ;
			wchara.byte2 = text->chara & 0x00FF ;
			XDrawString16( disp, win, gc, x, y, &wchara, 1 ) ;
			break ;
		default :
			continue ;
		}
		x += width ;
	}
	return x ;
}

/*
 * 差分描画関数、カーソル表示関係の処理なし、改行機能無し。
 *-----
 * もはや minibuffer の描画専用といった感があります。
 */
void
skkwin_jdiffputstring (
	register Display*		disp,
	register Window			win,
	register struct skkinputManagedFont**	fontset,
	register GC				gc,
	register GC				rgc,
	register int			x,
	register int			y,
	register int			width,
	register struct myChar*	text,
	register struct myChar*	ptext,
	register int			font_height,
	register int			font_ascent )
{
	register int x1, x2 ;

	/* x1 は現在の x2 は前の文字列の表示位置になっている。*/
	x1 = x2 = x ;

	/* 二つの文字列を比較する。*/
	while( !IS_END_OF_STRING( *text ) && x1 < width ){
		if( x1 == x2 ){
			/* 両者が同じ位置にあるので、同じ charset かつ同じ chara なら現
			 * 在の場所に表示する必要はない。*/
			if( text->chara == ptext->chara ){
				/* chara が同じだった場合には、charset が同じかどうかを判別す
				 * る。chara が違えば、charset がどうあれ、同じ文字であること
				 * はない。(と、する！) */
				if( text->charset == ptext->charset ){
					x1 += myCharTextWidth( fontset, text,  1 ) ;
					x2 += myCharTextWidth( fontset, ptext, 1 ) ;
					text ++ ;
					ptext ++ ;
					continue ;
				}
				/* ここまで来て continue されてなかったら、異なる文字だったと
				 * いうことになる。*/
			}
		} else if( x1 > x2 ){
			/* 文字列の最後まで来ていた場合には、問答無用で text の方を表示
			 * して欲しいが追いつくまで待ってしまうので、それを胡麻化す。*/
			if( IS_END_OF_STRING( *ptext ) ){
				x2 = width ;
				continue ;
			}
			x2 += myCharTextWidth( fontset, ptext, 1 ) ;
			ptext ++ ;
			continue ;
		}
		/* 以前に表示した文字列が先行してしまった場合には問答無用で再描
		 * 画して良い。また、charset や chara が異なっていた場合にもここに
		 * やって来ることになる。*/
		skkwin_jputMyChar (disp, win, fontset, gc, rgc, x1, y, *text, font_height, font_ascent, False) ;
		x1 += myCharTextWidth (fontset, text, 1) ;
		text ++ ;
	}
	/* 画面一杯まで表示されているので消去作業は必要無い。*/
	/* もしくは前回表示に使った分を超えて表示しているので。*/
	if( x1 >= width || IS_END_OF_STRING( *ptext ) )
		return ;
	/* 上書きされていない以前に描画した部分を消去する。*/
	XFillRectangle (disp, win, rgc, x1, y - font_ascent, width - x1, font_height) ;
	return ;
}

/*
 * カーソルを表示する関数。
 *----
 * int kf : 漢字フラグ。EUC 漢字コードなら True になる。
 */
void
skkinputDrawCursor (
	register Display*	disp,
	register Window		win,
	register GC			roman_ngc,
	register GC			roman_rgc, 
	register int		x,
	register int		y,
	register int		font_ascent,
	register int		width,
	register int		height,
	register int		is_focus)
{
	/* カーソルを表示する。*/
	if( is_focus ){
		XFillRectangle (disp, win, roman_ngc, x, y - font_ascent + 1, width - 1, height - 1) ;
	} else {
		XFillRectangle (disp, win, roman_rgc, x, y - font_ascent + 1, width - 1, height - 1) ;
		XDrawRectangle (disp, win, roman_ngc, x, y - font_ascent + 1, width - 1, height - 2) ;
	}
	return ;
}

/*
 *
 */
void
OTSW_CalcTopPositionOfBuffer (
	register struct skkinputManagedFont**	fontset,
	register struct myChar*		linetop,
	register int				linetop_pos,
	register int				cur_pos,
	register int				client_width,
	register struct myChar**	ret_toptext,
	register int*				ret_toppos)
{
	register struct myChar *text, *toptext ;
	register int toppos, pos, x, xdiff ;
  
	text    = linetop ;
	pos     = linetop_pos ;
	toppos  = linetop_pos ;
	toptext = linetop ;
	x       = 0 ;

	while (!IS_END_OF_STRING (*text)){
		/* 改行コードなら次の位置に修正が来る。*/
		if (IS_ASCII_EQUAL (*text, '\n')){
			/* カーソル位置を見付けると処理を抜ける。*/
			if( pos == cur_pos )
				break ;
			toppos  = pos  + 1 ;
			toptext = text + 1 ;
			x       = 0 ;
		} else {
			/* charset の判別とそれによるフォント幅の計算。*/
			xdiff = myCharTextWidth( fontset, text, 1 ) ;
			x += xdiff ;
			/* 改行するか否かを判断。*/
			if( x >= client_width ){
				toppos  = pos ;
				toptext = text ;
				x       = xdiff ;
			}
			/* カーソル位置を見付けると処理を抜ける。*/
			if( pos == cur_pos )
				break ;
		}
		pos ++ ;
		text ++ ;
	}
	*ret_toptext = toptext ;
	*ret_toppos  = toppos ;
	return ;
}

/*
 * トップバッファの一番上の行を表示する関数。
 *----
 * 引数が一杯で泣きそうとか。(笑)
 */
void
OTSW_FullDrawTopBufferTopLine (
	register Display*		disp,
	register Window			win,
	register struct skkinputManagedFont**	fontset,
	register GC				gc,
	register GC				rgc,
	register struct myChar*	text,
	register int			text_pos,
	register int			font_ascent,
	register int			font_height,
	register int			width,
	register int			bsflag, 
	register int			cursor_width,
	register int			cur_pos,
	register int			cur_exist,
	register int			is_focus)
{
	register int x = 0, xdiff = 0 ;
	register int cursor_flag = False ;
  
	/* そうじゃなかった場合の処理。*/
	for ( ; !IS_END_OF_STRING( *text ) && x < width ; text ++, text_pos ++){
		/* charset の判別とそれによるフォント幅の計算。*/
		xdiff = myCharTextWidth( fontset, text, 1 ) ;
		/* カーソルを表示する場所なのかどうかを判定する。*/
		if( text_pos == cur_pos && cur_exist ){
			if( !bsflag || ( x + xdiff ) < width ){
				skkinputDrawCursor (disp, win, gc, rgc, x, font_ascent, font_ascent, xdiff, font_height, is_focus ) ;
				cursor_flag = True ;
			}
		}
		/* 画面の右端まで描画したのかどうかを判断する。*/
		if ((x + xdiff) >= width && bsflag){
			XDrawLine( disp, win, gc, x, 0, width, font_height ) ;
			/* 一行表示だけなので、改行、それはすなわち終了。*/
			return ;
		}
		/* 改行コードを読んだ場合には、そこで終わる。*/
		if( IS_ASCII_EQUAL( *text, '\n' ) )
			return ;
		if( cursor_flag ){
			if( is_focus ){
				skkwin_jputMyChar (disp, win, fontset, rgc, gc, x, font_ascent, *text, font_height, font_ascent, True) ;
			} else {
				skkwin_jputMyChar (disp, win, fontset, gc, rgc, x, font_ascent, *text, font_height, font_ascent, True) ;
			}
			cursor_flag = False ;
		} else {
			skkwin_jputMyChar (disp, win, fontset, gc, rgc, x, font_ascent, *text, font_height, font_ascent, False) ;
		}
		x += xdiff ;
	}
	/* カーソルがテキストの後に存在した場合。*/
	if (cur_exist && text_pos == cur_pos){
		if ((!bsflag || (x + xdiff) < width)){
			skkinputDrawCursor (disp, win, gc, rgc, x, font_ascent, font_ascent, cursor_width, font_height, is_focus) ;
		} else {
			XDrawLine( disp, win, gc, x, 0, width, font_height ) ;
		}
	}
	return ;
}


/*
 * cur_line != NULL ならば、カーソルのあった場所が何行目であるかを返す。
 */
int
skkinput_GetLineNum (
	register struct skkinputManagedFont**	fontset,
	register struct myChar*	text,
	register unsigned int	width, 
	register int			cursor_width,
	register int			cur_pos,
	register int*			cur_line )
{
	register int num, cur_num, x, y, pos, xdiff ;
	register struct myChar *ptr ;
	
	/* 局所変数の初期化。*/
	x = y = pos = cur_num = num = 0 ;
	/* ループ。*/
	for (ptr = text ; !IS_END_OF_STRING (*ptr) ; ptr ++, pos ++){
		if (IS_ASCII_EQUAL (*ptr, '\n')){
			/* カーソル位置を記憶する。*/
			if (pos == cur_pos)
				cur_num = num ;
			x = 0 ;
			num ++ ;
		} else {
			xdiff = myCharTextWidth( fontset, ptr, 1 ) ;
			x += xdiff ;
			if( x >= width ){
				x = xdiff ;
				num ++ ;
			}
			/* カーソル位置を記憶する。*/
			if( pos == cur_pos )
				cur_num = num ;
		}
	}
	/* 未だにカーソルは発見されていない場合。*/
	if( pos <= cur_pos ){
		if( ( x + cursor_width ) > width )
			num ++ ;
		cur_num = num ;
	}
	/* カーソルの位置を返すのかな？ */
	if( cur_line != NULL )
		*cur_line = cur_num ;
	return num ;
}

/*
 * 表示すべき領域の大きさが分かっている時に文字列の何処の位置から表示
 * するかを求める関数。
 */
int
skkinput_FindStartLine (
	register struct skkinputManagedFont**	fontset,
	register struct myChar*	text, 
	register int			startline,
	register unsigned int	width )
{
	register int x, pos, xdiff ;
	register struct myChar *ptr ;

	/* 局所変数の初期化。*/
	x = pos = 0 ;
	ptr = text ;
	/* ループ。*/
	while( startline > 0 && !IS_END_OF_STRING( *ptr ) ){
		if( IS_ASCII_EQUAL( *ptr, '\n' ) ){
			x = 0 ;
			startline -- ;
		} else {
			xdiff = myCharTextWidth( fontset, ptr, 1 ) ;
			x += xdiff ;
			if( x >= width ){
				x = xdiff ;
				startline -- ;
				if( startline <= 0 )
					break ;
			}
		}
		ptr ++ ; pos ++ ;
	}
	return pos ;
}

/*
 * Window manager の情報を書換える関数。
 */
void
XChangeWMNormalHints (
	register Display*		disp,
	register Window			win,
	register XSizeHints*	hints)
{
	XSizeHints sizehints ;
	long supplied ;

	/* Window Manager にヒントを送っている。ただし、XSetWMNormalHints * 
	 * は部分書換えしないようなので、以前の hints を読みとってから差し*
	 * 替えるという手法をとらなければならない。*/
	XGetWMNormalHints (disp, win, &sizehints, &supplied) ;
	/*
	 * ここから、フラグを見て修正するという作業を行う。
	 */
	
	/* ウィンドウの表示位置の原点を何処にとるか。*/
	if( hints->flags & PWinGravity ){
		sizehints.flags |= PWinGravity ;
		sizehints.win_gravity = hints->win_gravity ;
	}
	/* ウィンドウのベースサイズの設定。*/
	if( hints->flags & PBaseSize ){
		sizehints.flags |= PBaseSize ;
		sizehints.base_width  = hints->base_width ;
		sizehints.base_height = hints->base_height ;
	}
	/* ウィンドウの最小の大きさを設定。*/
	if( hints->flags & PMinSize ){
		sizehints.flags |= PMinSize ;
		sizehints.min_width  = hints->min_width ;
		sizehints.min_height = hints->min_height ;
	}
	/* ウィンドウの最大の大きさを設定。*/
	if( hints->flags & PMaxSize ){
		sizehints.flags |= PMaxSize ;
		sizehints.max_width  = hints->max_width ;
		sizehints.max_height = hints->max_height ;
	}
	/* ウィンドウの増分(変化の幅)を設定。*/
	if( hints->flags & PResizeInc ){
		sizehints.flags |= PResizeInc ;
		sizehints.width_inc  = hints->width_inc ;
		sizehints.height_inc = hints->height_inc ;
	}
	/* 再設定する。*/
	XSetWMNormalHints( disp, win, &sizehints ) ;
	return ;
}

/*
 * 指定された窓の大きさ、位置の情報を XRectangle 構造体に入れて返す関数。
 */
void
XGetRectangleOfWindow (
	register Display*		disp,
	register Window			win,
	register XRectangle*	area)
{
	Window rootwin ;
	int x, y ;
	unsigned int border_width, depth_size, height, width ;
  
	XGetGeometry (disp, win, &rootwin, &x, &y, &width, &height, &border_width, &depth_size) ;
	area->x			= (short) x ;
	area->y			= (short) y ;
	area->width		= (unsigned short) width ;
	area->height	= (unsigned short) height ;
	return ;
}

/*
 * 渡された skkinput のモードラインが何であるのかを調べる関数。
 */
int
skkinput_GetModelineNumber (
	register struct SKKInputNode*	node)
{
	int modeline ;
	/* 仮名入力モードなの？ そうではないの？ */
	if( !node->j_mode ){
		/* 全角入力モードなの？ 半角入力モードなの？ */
		if( node->j_zenkaku ){
			modeline = MODELINE_ZENKAKU ;
		} else {
			modeline = MODELINE_HANKAKU ;
		}
	} else {
		/* 片仮名入力モードなの？ 平仮名入力モードなの？ */
		if( node->j_katakana_mode ){
			modeline = MODELINE_KATAKANA ;
		} else {
			modeline = MODELINE_KANA ;
		}
	}
	return modeline ;
}

/*
 * 日本語 Extended Unix Code からなる文字列を表示する関数。
 *---
 */
int
skkwin_jputCharString (
	register Display*		disp,
	register Window			win,
	register struct skkinputManagedFont**	fontset,
	register GC				gc,
	register int			x,
	register int			y,
	register unsigned char*	text)
{
	register XFontStruct *font = NULL ;
	XChar2b wchara ;

	for( ; *text != '\0' ; ){
		if( ( *text ) & 0x80 ){
			switch( *text ){
			case 0x8E :
				text ++ ;
				if( fontset[ CHARSET_JISX0201_1976 ] != NULL ){
					if( font != fontset[ CHARSET_JISX0201_1976 ]->font ){
						font = fontset[ CHARSET_JISX0201_1976 ]->font ;
						XSetFont( disp, gc, font->fid ) ;
					}
					XDrawString( disp, win, gc, x, y, text, 1 ) ;
					x += XTextWidth( font, text, 1 ) ;
				} else {
					x += DEFAULT_TOFU_WIDTH ;
				} 
				text ++ ;
				break ;
			case 0x8F :
				text ++ ;
				if( fontset[ CHARSET_JISX0212_1990 ] != NULL ){
					if( font != fontset[ CHARSET_JISX0212_1990 ]->font ){
						font = fontset[ CHARSET_JISX0212_1990 ]->font ;
						XSetFont( disp, gc, font->fid ) ;
					}
					wchara.byte1 = ( text[ 0 ] ) & 0x7F ;
					wchara.byte2 = ( text[ 1 ] ) & 0x7F ;
					XDrawString16
						( disp, win, gc, x, y, &wchara, 1 ) ;
					x += XTextWidth16( font, &wchara, 1 ) ;
				} else {
					x += DEFAULT_TOFU_WIDTH ;
				}
				text ++ ;
				text ++ ;
				break ;
			default :
				if( fontset[ CHARSET_JISX0208_1983 ] != NULL ){
					if( font != fontset[ CHARSET_JISX0208_1983 ]->font ){
						font = fontset[ CHARSET_JISX0208_1983 ]->font ;
						XSetFont( disp, gc, font->fid ) ;
					}
					wchara.byte1 = ( text[ 0 ] ) & 0x7F ;
					wchara.byte2 = ( text[ 1 ] ) & 0x7F ;
					XDrawString16( disp, win, gc, x, y, &wchara, 1 ) ;
					x += XTextWidth16( font, &wchara, 1 ) ;
				} else {
					x += DEFAULT_TOFU_WIDTH ;
				}
				text ++ ;
				text ++ ;
				break ;
			}
		} else {
			if( fontset[ CHARSET_ASCII ] != NULL ){
				if( font != fontset[ CHARSET_ASCII ]->font ){
					font = fontset[ CHARSET_ASCII ]->font ;
					XSetFont( disp, gc, font->fid ) ;
				}
				XDrawString( disp, win, gc, x, y, text, 1 ) ;
				x += XTextWidth( font, text, 1 ) ;
			} else {
				x += DEFAULT_TOFU_WIDTH ;
			}
			text ++ ;
		}
	}
	return x ;
}

/*
 * テキストを表示するのに必要な幅(width)を求める関数。
 */
int
skkwin_charTextWidth (
	register struct skkinputManagedFont**	fontset,
	register unsigned char*	string,
	register int			num)
{
	XChar2b wchara ;
	register int width ;

	width = 0 ;
	while (*string != '\0' && num > 0){
		if ((*string) & 0x80){
			wchara.byte1 = (*string ++) & 0x7F ;
			num -- ;
			wchara.byte2 = (*string ++) & 0x7F ;
			num -- ;
			if (fontset [CHARSET_JISX0208_1983] != NULL){
				width += XTextWidth16 (fontset [CHARSET_JISX0208_1983]->font, &wchara, 1) ;
			} else {
				width += DEFAULT_TOFU_WIDTH ;
			}
		} else {
			if (fontset [CHARSET_ASCII] != NULL){
				width += XTextWidth (fontset [CHARSET_ASCII]->font, string, 1) ;
			} else {
				width += DEFAULT_TOFU_WIDTH ;
			}
			string ++ ;
			num -- ;
		}
	}
	return width ;
}

/*
 * テキストを表示するのに必要な幅(width)を求める関数。
 */
int
myCharTextWidth (
	register struct skkinputManagedFont**	fontset,
	register const struct myChar*	wstring,
	register int					num )
{
	char    schara ;
	XChar2b wchara ;
	register int width ;

	width = 0 ;
	while (num > 0 && !IS_END_OF_STRING (*wstring)){
		if (fontset [(int)wstring->charset] != NULL){
			switch (wstring->charset){
			case CHARSET_ISO8859_1 :
			case CHARSET_ISO8859_2 :
			case CHARSET_ISO8859_3 :
			case CHARSET_ISO8859_4 :
			case CHARSET_ISO8859_5 :
			case CHARSET_ISO8859_6 :
			case CHARSET_ISO8859_7 :
			case CHARSET_ISO8859_8 :
			case CHARSET_ISO8859_9 :
			case CHARSET_JISX0201_1976 :
				schara = wstring->chara ;
				width += XTextWidth (fontset [(int)wstring->charset]->font, &schara, 1) ;
				break ;
			case CHARSET_JISX0208_1978 :
			case CHARSET_JISX0208_1983 :
			case CHARSET_JISX0212_1990 :
			case CHARSET_GB2312_1980 :
			case CHARSET_KSC5601_1987 :
				wchara.byte1 = (wstring->chara) >> 8 ;
				wchara.byte2 = (wstring->chara) & 0x00FF ;
				width += XTextWidth16 (fontset [(int)wstring->charset]->font, &wchara, 1) ;
				break ;
			default :
				width += DEFAULT_TOFU_WIDTH ;
				break ;
			}
		} else {
			width += DEFAULT_TOFU_WIDTH ;
		}
		wstring ++ ;
		num -- ;
	}
	return width ;
}

/*
 * モードラインを描画する関数。
 */
int
getWidthOfModeLine (
	register struct skkinputManagedFont**	fontset,
	register struct SKKInputNode*	node,
	register int					jisyo_dirty,
	register int					overthespot_like_input)
{
	register int modeline = skkinput_GetModelineNumber( node ) ;
	register int width ;

	width  = skkwin_charTextWidth (fontset, skkinput_ModelineStrings [modeline - 1], 32) ;
	width += skkwin_charTextWidth (fontset, skkinput_ModelineStringsJisyo [jisyo_dirty], 1) ;
	width += skkwin_charTextWidth (fontset, skkinput_ModelineStringsOverTheSpot [(overthespot_like_input & 1)], 1) ;
	return	width ;
}

int
GetModeLineText (
	register struct SKKInputNode*			node,
	register int							jisyo_dirty,
	register int							overthespot_like_input,
	register struct myChar*					pBuffer)
{
	register int	modeline = skkinput_GetModelineNumber (node) ;

	if (modeline < 1 || modeline > NUMBER_OF_MODELINE)
		return	0 ;

	if (pBuffer != NULL) {
		register struct myChar*			pDest ;
		register const struct myChar*	pMySrc ;
		register const char*			pSrc ;

		pDest	= pBuffer ;
		pMySrc	= rstrModeline [modeline - 1] ;
		while (! IS_END_OF_STRING (*pMySrc)) 
			*pDest	++	= *pMySrc ++ ;

		pSrc	= skkinput_ModelineStringsJisyo [jisyo_dirty] ;
		while (*pSrc != '\0') {
			pDest->charset	= CHARSET_ASCII ;
			pDest->chara	= *pSrc ++ ;
			pDest	++ ;
		}
		pSrc	= skkinput_ModelineStringsOverTheSpot [(overthespot_like_input & 1)] ;
		while (*pSrc != '\0') {
			pDest->charset	= CHARSET_ASCII ;
			pDest->chara	= *pSrc ++ ;
			pDest	++ ;
		}
		pDest->charset	= CHARSET_ASCII ;
		pDest->chara	= '\0' ;
		return	(pDest - pBuffer) ;
	} else {
		register int	nUsage ;

		nUsage	=  srnLengthModeline [modeline - 1] ;
		nUsage	+= strlen (skkinput_ModelineStringsJisyo [jisyo_dirty]) ;
		nUsage	+= strlen (skkinput_ModelineStringsOverTheSpot [(overthespot_like_input & 1)]) ;
		return	nUsage ;
	}
}

/*
 * モードラインを描画する関数。
 */
void
fullDrawModeLine (
	register Display*						disp,
	register Window							win,
	register struct skkinputManagedFont**	fontset,
	register GC								gc,
	register struct SKKInputNode*			node,
	register int							x,
	register int							y,
	register int							jisyo_dirty,
	register int							overthespot_like_input)
{
	register int modeline = skkinput_GetModelineNumber (node) ;

	/* モードラインを表示する( SKKのモード表示 )。*/
	x	= skkwin_jputstring (disp, win, fontset, gc, x, y, rstrModeline [modeline - 1]) ;
	/* モードラインを表示する( 辞書の情報を表示 )。*/
	x = skkwin_jputCharString (disp, win, fontset, gc, x, y, skkinput_ModelineStringsJisyo [jisyo_dirty]) ;
	skkwin_jputCharString (disp, win, fontset, gc, x, y, skkinput_ModelineStringsOverTheSpot [(overthespot_like_input & 1)]) ;
	return ;
}

/*
 * モードラインを表示するのにどの程度の文字幅が必要なのかを求める関数。
 */
int
getMaxLengthOfModeline (
	register struct skkinputManagedFont**	fontset)
{
	register int width, max_width, ret, i ;

	max_width = 0 ;
	for (i = 0 ; i < NUMBER_OF_MODELINE ; i ++){
		width	= myCharTextWidth (fontset, rstrModeline [i], srnLengthModeline [i]) ;
		if (max_width < width)
			max_width = width ;
	}
	ret			= max_width ;
	max_width	= 0 ;
	for (i = 0 ; i < NUMBER_OF_MODELINE_OVERTHESPOT ; i ++){
		width = skkwin_charTextWidth (fontset, skkinput_ModelineStringsOverTheSpot [i], 1) ;
		if (max_width < width)
			max_width = width ;
	}
	return (ret + (max_width << 1)) ;
}
