/* # skkinput (Simple Kana-Kanji Input)
 * OnWin.c --- Making OnTheSpotWinWidget.
 * This file is part of skkinput.
 * Copyright (C) 2002
 * 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 <limits.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>

#include "OnWinP.h"
#include "config.h"
#include "skkkey.h"
#include "skkel.h"
#include "Canvas.h"
#include "WmcloseShell.h"
#include "MyError.h"
#include "draw.h"
#include "MyDispatch.h"

#ifndef XtNgeometry
#define XtNgeometry		"geometry"
#define XtCGeometry		"Geometry"
#endif

#define offset(field)	XtOffsetOf (OnthespotWinRec, onthespotWin.field)
#define goffset(field)	XtOffsetOf (WidgetRec, core.field)

static XtResource OnWin_resources[] = {
	/* もとからあるリソース。*/
	{ XtNwidth,			XtCWidth,		XtRDimension,	sizeof(Dimension),
	  goffset(width),	XtRImmediate,	(XtPointer) 400},
	{ XtNheight,		XtCHeight,		XtRDimension,	sizeof(Dimension),
	  goffset(height),	XtRImmediate,	(XtPointer) 400},
	/* ミニバッファの大きさを指定する…。デフォルトのね。一度、リサイズ *
	 * したら覚えるようにしようか？ */
	{ XtNmwidth,		XtCMwidth,		XtRDimension,	sizeof(Dimension),
	  offset(minibuf_width),	XtRImmediate,	(XtPointer)640 },
	/* 自分とこで作ったリソース。*/
	{ XtNforeground,	XtCForeground,	XtRPixel,		sizeof(Pixel),
	  offset(puppixel),	XtRString,		XtDefaultForeground },
	/* Minibuffer を反転表示するかどうかとかいう話になる。*/
	{ XtNreverseVideo,	XtCReverseVideo,	XtRBoolean,	sizeof (Boolean),
	  offset(reverse_video),	XtRImmediate,	(XtPointer) FALSE},
	/* Onthespot で利用する漢字フォント及びローマ字フォント。*/
	{ XtNfontset,		XtCFontset,	XtRString,	sizeof (String),
	  offset(fontset_string),	XtRImmediate,	(XtPointer)DEFAULT_FONTSET },
	/* Minibuffer Window を描画するのに利用する漢字及びローマ字フォント。*/
	{ XtNmfontset, XtCFontset,  XtRString, sizeof (String),
	  offset(minibuf_fontset_string), XtRImmediate, DEFAULT_FONTSET },
	/* Minibuffer Window の大きさがフォントの修正に左右されるかどうか。*/
	{ XtNchangeMinibufferFont, XtCChangeMinibufferFont,
	  XtRBoolean, sizeof (Boolean),
	  offset(change_minibuffer_font), XtRImmediate, (XtPointer)TRUE },
	/* skkinput 窓が閉じる時に利用される callback */
	{ XtNendNotify, XtCCallback, XtRCallback, sizeof(caddr_t), 
	  offset(endcallback), XtRCallback, (caddr_t)NULL },
	/* skkinput から client に文字列を送信する時に利用される callback */
	{ XtNfixNotify, XtCCallback, XtRCallback, sizeof (caddr_t), 
	  offset(fixcallback), XtRCallback, (caddr_t)NULL },
	/* key event を client に送り返す時に利用される callback */
	{ XtNkeybackNotify, XtCCallback, XtRCallback, sizeof (caddr_t), 
	  offset(keybackcallback), XtRCallback, (caddr_t)NULL },
	/* egg 互換の j-newline を許すか否か。*/
	{ XtNeggLikeNewline, XtCEggLikeNewline, XtRImmediate, sizeof (Boolean),
	  XtOffsetOf (OnthespotWinRec, onthespotWin.buffer.egg_like_newline),
	  XtRImmediate, (XtPointer) FALSE},
	/* chat-adapter-mode か否か。*/
	{ XtNchatAdapter, XtCChatAdapter, XtRImmediate, sizeof (Boolean),
	  XtOffsetOf (OnthespotWinRec, onthespotWin.buffer.chat_adapter),
	  XtRImmediate, (XtPointer) FALSE},
	{ XtNjisyoDirty, XtCJisyoDirty, XtRImmediate, sizeof (Boolean),
	  XtOffsetOf (OnthespotWinRec, onthespotWin.buffer.jisyo_dirty),
	  XtRImmediate, (XtPointer) FALSE },
	/* 変換属性の指定。*/
	{ XtNconversionAttribute, XtCConversionAttribute, XtRImmediate, 
	  sizeof (struct ConvAttrsMesg *),
	  offset (camsg), XtRImmediate,  (XtPointer)NULL },
	/* ミニバッファの消去を受ける。*/
	{ XtNclearMinibuffer, XtCClearMinibuffer, XtRImmediate, sizeof (Boolean),
	  offset (clearMinibuffer), XtRImmediate, (XtPointer)FALSE },
	{ XtNclientWindow, XtCClientWindow, XtRImmediate, sizeof (Window),
	  offset (client_window), XtRImmediate, (XtPointer)None },
	{ XtNsetFocus, XtCSetFocus, XtRImmediate, sizeof (int),
	  offset (conversion_set_focus), XtRImmediate, (XtPointer)FALSE },
	{ XtNunsetFocus, XtCUnsetFocus, XtRImmediate, sizeof (int),
	  offset (conversion_unset_focus), XtRImmediate, (XtPointer)FALSE  },
	/* history の初期化に用いる関数。*/
	{ XtNconversionHistory, XtCConversionHistory, XtRImmediate,
	  sizeof (HistoryListNode *), offset (historyAttribute),
	  XtRImmediate,  (XtPointer)NULL },
	{ XtNoverTheSpotLikeInput, XtCOverTheSpotLikeInput, XtRBoolean,
	  sizeof (Boolean), offset (overthespotLikeInput),
	  XtRImmediate,  (XtPointer)TRUE },
	{ XtNshiftHaTugiDeYukou, XtCShiftHaTugiDeYukou, XtRBoolean,
	  sizeof (Boolean), 
	  XtOffsetOf (OnthespotWinRec, onthespotWin.buffer.toggleShiftMode),
	  XtRImmediate,  (XtPointer)FALSE },
	{ XtNcontrolHaTugiDeYukou, XtCControlHaTugiDeYukou, XtRBoolean,
	  sizeof (Boolean), 
	  XtOffsetOf (OnthespotWinRec, onthespotWin.buffer.toggleControlMode),
	  XtRImmediate,  (XtPointer)FALSE },
	{ XtNmodeshell_geometry, XtCModeShell_Geometry, XtRString,
	  sizeof (String),
	  XtOffsetOf (OnthespotWinRec, onthespotWin.modeshell_geometry),
	  XtRImmediate, (XtPointer)DEFAULT_MODELINE_GEOMETRY},
	{	XtNpreeditStartCallback,	XtCCallback,
		XtRCallback,				sizeof (XtCallbackList),
		offset (m_lstCbkPreeditStart),	XtRCallback,		(XtPointer) NULL, },
	{	XtNpreeditDrawCallback,	XtCCallback,
		XtRCallback,				sizeof (XtCallbackList),
		offset (m_lstCbkPreeditDraw),	XtRCallback,		(XtPointer) NULL, },
	{	XtNpreeditCaretCallback,	XtCCallback,
		XtRCallback,				sizeof (XtCallbackList),
		offset (m_lstCbkPreeditCaret),	XtRCallback,		(XtPointer) NULL, },
	{	XtNpreeditDoneCallback,	XtCCallback,
		XtRCallback,				sizeof (XtCallbackList),
		offset (m_lstCbkPreeditDone),	XtRCallback,		(XtPointer) NULL, },
	{	XtNstatusStartCallback,	XtCCallback,
		XtRCallback,				sizeof (XtCallbackList),
		offset (m_lstCbkStatusStart),	XtRCallback,		(XtPointer) NULL, },
	{	XtNstatusDrawCallback,	XtCCallback,
		XtRCallback,				sizeof (XtCallbackList),
		offset (m_lstCbkStatusDraw),	XtRCallback,		(XtPointer) NULL, },
	{	XtNstatusDoneCallback,	XtCCallback,
		XtRCallback,				sizeof (XtCallbackList),
		offset (m_lstCbkStatusDone),	XtRCallback,		(XtPointer) NULL, },
	{	XtNtextNotify,			XtCCallback,
		XtRCallback,				sizeof (XtCallbackList),
		offset (m_lstTextCallback),		XtRCallback,		(XtPointer) NULL },
	{	XtNinput, 				XtCInput,
		XtRBoolean,					sizeof (Boolean), 
		offset (m_fInputFocus),			XtRImmediate,		(XtPointer) TRUE },
} ;

#undef offset
#undef goffset

/*
 * プロトタイプ宣言。
 */
/*
 * このウィジェットを構成している基本要素となる関数たち。
 */
static void		OnWin_Initialize	(Widget, Widget, ArgList, Cardinal*) ;
static void		OnWin_Realize		(Widget, XtValueMask*, XSetWindowAttributes*) ;
static void		OnWin_Destroy		(Widget) ;
static Boolean	OnWin_SetValues		(Widget, Widget, Widget, ArgList, Cardinal*) ;
static void		KeyDownEventHandler	(Widget, XEvent*, String*, Cardinal*) ;
static void		FocusEventHandler	(Widget, XEvent*, String*, Cardinal*) ;

static void		OnWin_Clear			(Widget) ;
static void		OnWin_Display		(Widget) ;
static void		OnWin_CreateMinibufferGCs	(Widget) ;
static void		OnWin_ReleaseMinibufferGCs	(Widget) ;
static void		Modeshell_Clear		(Widget) ;
static void		Modeshell_Display	(Widget) ;
static void		OnWin_popup			(Widget) ;
static void		OnWin_popdown		(Widget) ;
static int		OnWin_ChangeAttributes	(Widget, unsigned long, struct ConvAttrs*) ;
static void		OnWin_ConfigureMinibuffer (Widget) ;
static void		OnWin_RedrawScreen		(Widget) ;
static void		Minibuffer_Redisplay	(Widget, Window) ;
static void		OnWin_fixcallback		(Widget, XtPointer, XtPointer) ;

/*
 * callbacks
 */
static void		Minibuffer_RedisplayCallback (Widget, caddr_t, caddr_t) ;
static void		OnWin_wmMessageCloseCallback (Widget, caddr_t, caddr_t) ;
static void		OnWin_wmShellDestroyCallback (Widget, caddr_t, caddr_t) ;
static void		Canvas_DestroyCallback		 (Widget, caddr_t, caddr_t) ;

/* common style */
extern void		skkinput_bufferInit		(struct skkinputBuffer*) ;
extern int		commonKeyEventHandler	(Widget, XEvent*, struct skkinputBuffer*) ;
extern void		force_keyboard_quit		(Widget, struct skkinputBuffer*) ;

/*
 * グローバル変数。
 */
static XtActionsRec	onthespotWinActionsTable [] = {
	{ "KeyDownEventHandler",	   KeyDownEventHandler },
	{ "FocusInEventHandler",	   FocusEventHandler },
	{ "FocusOutEventHandler",	   FocusEventHandler },
} ;

static char		defaultOnthespotWinTranslations[] =  
"<Key>:                   KeyDownEventHandler()\n\
 <KeyRelease>:            KeyDownEventHandler()\n\
 <FocusIn>:               FocusInEventHandler()\n\
 <FocusOut>:              FocusOutEventHandler()\n" ;

OnthespotWinClassRec	onthespotWinClassRec = {
    {	/* core fields */
		/* superclass			*/	&widgetClassRec,
		/* class_name			*/	"Onthespot",
		/* size					*/	sizeof (OnthespotWinRec),
		/* class_initialize		*/	NULL,
		/* class_part_initialize*/	NULL,
		/* class_inited			*/	FALSE,
		/* initialize			*/	OnWin_Initialize,
		/* initialize_hook		*/	NULL,
		/* realize				*/	OnWin_Realize,
		/* actions				*/	onthespotWinActionsTable,
		/* num_actions			*/	XtNumber (onthespotWinActionsTable),
		/* resources			*/	OnWin_resources,
		/* num_resources		*/	XtNumber (OnWin_resources),
		/* xrm_class			*/	NULLQUARK,
		/* compress_motion		*/	TRUE,
		/* compress_exposure	*/	TRUE,
		/* compress_enterleave	*/	TRUE,
		/* visible_interest		*/	FALSE,
		/* destroy				*/	OnWin_Destroy,
		/* resize				*/	NULL,
		/* expose				*/	NULL,
		/* set_values			*/	OnWin_SetValues,
		/* set_values_hook		*/	NULL,
		/* set_values_almost	*/	XtInheritSetValuesAlmost,
		/* get_values_hook		*/	NULL,
		/* accept_focus			*/	NULL,
		/* version				*/	XtVersion,
		/* callback_private		*/	NULL,
		/* tm_table				*/	defaultOnthespotWinTranslations,
		/* query_geometry		*/	XtInheritQueryGeometry,
    }
} ;

WidgetClass onthespotWinWidgetClass	= (WidgetClass)&onthespotWinClassRec ;

static void
OnWin_InitializeHistory (
	register Widget		gw)
{
	register OnthespotWinWidget w =  (OnthespotWinWidget)gw ;

	if (w->onthespotWin.historyAttribute == NULL){
		return ;
	}
	/* 以前に設定したことがあれば…。*/
	if (w->onthespotWin.historyAttribute->overthespot_like_input == False){
		/* X Resource の側から設定する。*/
		w->onthespotWin.buffer.overthespot_like_input = 
			w->onthespotWin.overthespotLikeInput ;
	} else {
		/* 前回の設定を流用する。*/
		w->onthespotWin.buffer.overthespot_like_input = 
			w->onthespotWin.historyAttribute->overthespot_like_input ;
	}
	/* ヒストリの初期化をする。これはモード切り替えで、一行入力モード
	   に移動されてしまった時のための保険である。*/
	w->onthespotWin.buffer.historybuffer =
		w->onthespotWin.historyAttribute->history ;
	w->onthespotWin.buffer.hist_start = 
		w->onthespotWin.historyAttribute->history_start ;
	w->onthespotWin.buffer.hist_end = 
		w->onthespotWin.historyAttribute->history_end ;
	w->onthespotWin.buffer.histcurbackbuffer =
		w->onthespotWin.historyAttribute->histcurbak ;
	w->onthespotWin.buffer.hist_cur = -1 ;
	
	w->onthespotWin.buffer.chat_adapter =
		w->onthespotWin.historyAttribute->chat_adapter ;
	w->onthespotWin.buffer.egg_like_newline =
		w->onthespotWin.historyAttribute->egg_nl ;
	
	w->onthespotWin.buffer.topbuffer->j_mode =
		w->onthespotWin.historyAttribute->j_mode ;
	w->onthespotWin.buffer.topbuffer->j_zenkaku =
		w->onthespotWin.historyAttribute->j_zenkaku ;
	w->onthespotWin.buffer.topbuffer->j_katakana_mode =
		w->onthespotWin.historyAttribute->j_katakana_mode ;
	return ;
}

static void
OnWin_Initialize (
	register Widget		greq,
	register Widget		gnew,
	register ArgList	args, 
	register Cardinal*	num_args)
{
	register Display*			pDisplay	= XtDisplay (gnew) ;
	register OnthespotWinWidget w			=  (OnthespotWinWidget)gnew ;
	register int				i ;

	/* colormap 及びフォアグラウンド／バックグラウンドカラーの初期化を行
	 * う。*/ 
	w->onthespotWin.background = w->core.background_pixel ;
	w->onthespotWin.foreground = w->onthespotWin.puppixel ;
	w->onthespotWin.colormap   = w->core.colormap ;

	w->onthespotWin.oforeground = w->onthespotWin.foreground ;
	w->onthespotWin.obackground = w->onthespotWin.background ;

	for (i = 0 ; i < NUMBER_OF_CHARSET ; i ++) {
		w->onthespotWin.fontset [i]			= NULL ;
		w->onthespotWin.minibuf_fontset [i]	= NULL ;
	}

	w->onthespotWin.minibuf_gc = w->onthespotWin.minibuf_rgc = NULL ;

	/* デフォルトのフォントを設定しておく。*/
	fontMgr_copyDefaultMinibufFontSet (pDisplay, w->onthespotWin.fontset) ;
	fontMgr_copyDefaultMinibufFontSet (pDisplay, w->onthespotWin.minibuf_fontset) ;

	/* フォントの大きさの情報を抜き出しておく。*/
	fontMgr_GetFontSetInfo (w->onthespotWin.fontset, &w->onthespotWin.font_height, &w->onthespotWin.font_ascent) ;
	fontMgr_GetFontSetInfo (w->onthespotWin.minibuf_fontset, &w->onthespotWin.mfont_height, &w->onthespotWin.mfont_ascent) ;

	/* バッファの初期化をしておく。*/
	skkinput_bufferInit (&(w->onthespotWin.buffer)) ;
	w->onthespotWin.buffer.redraw		= OnWin_RedrawScreen ;
	/* w->onthespotWin.buffer.overthespot_like_input = True ; */

	w->onthespotWin.minibuffer_probe	= False ;
	w->onthespotWin.modeshell_probe 	= False ;

	w->onthespotWin.attribute_mask		= 0L ;

	/* カーソルの大きさの設定。*/
	w->onthespotWin.cursor_width		= 8 ;

	/* ヒストリの初期化をする。*/
	OnWin_InitializeHistory (gnew) ;

    w->onthespotWin.minibuffer_win = None ;

	w->onthespotWin.m_fPreeditActive	= False ;
	w->onthespotWin.m_fActive			= False ;
	MYCHAR_SET_END_OF_STRING (w->onthespotWin.m_strPreeditText [0]) ;
	w->onthespotWin.m_nPreeditCaret		= 0 ;

	MYCHAR_SET_END_OF_STRING (w->onthespotWin.m_strModeText [0]) ;
	w->onthespotWin.m_nModeTextLen	= 0 ;
	return ;
}

static void OnWin_ReleaseMinibufferGCs (Widget gw)
{
	register OnthespotWinWidget w =  (OnthespotWinWidget)gw ;
	if (w->onthespotWin.minibuf_gc != NULL)
		XFreeGC (XtDisplay (gw), w->onthespotWin.minibuf_gc) ;
	if (w->onthespotWin.minibuf_rgc != NULL)
		XFreeGC (XtDisplay (gw), w->onthespotWin.minibuf_rgc) ;
	w->onthespotWin.minibuf_gc = w->onthespotWin.minibuf_rgc = NULL ;
	return ;
}

static void
OnWin_FreeFontSet (
	register Widget		gw)
{
	register OnthespotWinWidget 	w =  (OnthespotWinWidget)gw ;
	register Display*				pDisplay ;
	register int					i ;
	register struct skkinputManagedFont**	ppFont ;
	register struct skkinputManagedFont**	ppMFont ;

	pDisplay	= XtDisplay (gw) ;
	ppFont		= w->onthespotWin.fontset ;
	ppMFont		= w->onthespotWin.minibuf_fontset ;
	for (i = 0 ; i < NUMBER_OF_CHARSET ; i ++){
		fontMgr_FreeFont (pDisplay, *ppFont ++) ;
		fontMgr_FreeFont (pDisplay, *ppMFont ++) ;
	}
	return ;
}

static void
OnWin_CreateMinibufferGCs (
	register Widget		gw)
{
	register OnthespotWinWidget	w			=  (OnthespotWinWidget)gw ;
	register Display*			pDisplay	= XtDisplay (gw) ;
	register Window				wndCanvas ;
	XGCValues	values ;

	/* 画面に貼り付くタイプのミニバッファならば作る必要はない。*/
	if (w->onthespotWin.minibuffer_win != None)
		return ;

	/* 色の変化は受けないようにする。理由は簡単。カラーマップが異なる可
	 * 能性があるからです。じゃあ、カラーマップを一緒にしよう…、DEPTH 
	 * が違う可能性があります。DEPTH も一緒にしよう…って？  */
	wndCanvas			= XtWindow (w->onthespotWin.minibuffer_canvas) ;
	values.foreground	= w->onthespotWin.foreground ;
	values.background	= w->onthespotWin.background ;
	w->onthespotWin.minibuf_gc	= XCreateGC (pDisplay, wndCanvas, GCForeground | GCBackground, &values) ;
	values.foreground	= w->onthespotWin.background ;
	values.background	= w->onthespotWin.foreground ;
	w->onthespotWin.minibuf_rgc	= XCreateGC (pDisplay, wndCanvas, GCForeground | GCBackground, &values) ;
	return ;
}

/*
 * ミニバッファ窓を実体化させるのに呼び出される関数。
 */
static void
OnWin_RealizeMinibuffer (
	register Widget		gw)
{
	register OnthespotWinWidget	w	=  (OnthespotWinWidget)gw ;
	register Widget				minibuffer_popup ;
	register Widget				minibuffer_canvas ;
	XSizeHints sizehints ;
	unsigned int winwidth, winheight, font_height ;

	winwidth  = w->onthespotWin.minibuf_width ;
	if (w->onthespotWin.change_minibuffer_font){
		winheight   = w->onthespotWin.font_height ;
		font_height = w->onthespotWin.font_height ;
	} else {
		winheight   = w->onthespotWin.mfont_height ;
		font_height = w->onthespotWin.mfont_height ;
	}
	minibuffer_popup	= XtVaCreatePopupShell (
		"minibuffer", wmcloseShellWidgetClass, gw,
		XtNinput,				w->onthespotWin.m_fInputFocus,
		XtNmappedWhenManaged,	TRUE, 
		XtNwidth,				winwidth,
		XtNheight,				winheight, 
		XtNcolormap,			gw->core.colormap,
		XtNreverseVideo,		w->onthespotWin.reverse_video,
		XtNbackground,			w->onthespotWin.background,
		XtNforeground,			w->onthespotWin.foreground,
		NULL) ;
	XtAddCallback (minibuffer_popup, XtNwmcloseNotify, (XtCallbackProc)OnWin_wmMessageCloseCallback, gw) ;
	XtAddCallback (minibuffer_popup, XtNdestroyNotify, (XtCallbackProc)OnWin_wmShellDestroyCallback, gw) ;
	
	/* その下につく表示用の widget を作成する。以前、shellwidget に直 *
	 * 接書いてはまったことがあるので…。*/
	minibuffer_canvas	= XtVaCreateManagedWidget (
		"canvas", canvasWidgetClass, minibuffer_popup,
		XtNinput,				w->onthespotWin.m_fInputFocus,
		XtNreverseVideo,		w->onthespotWin.reverse_video,
		XtNbackground,			w->onthespotWin.background, 
		XtNforeground,			w->onthespotWin.foreground,
		NULL) ;
	w->onthespotWin.minibuffer_probe = False ;
	/* 再描画イベントを奪っておく。*/
	XtAddCallback (minibuffer_canvas, XtNredrawNotify,  (XtCallbackProc)Minibuffer_RedisplayCallback, gw) ;
	XtAddCallback (minibuffer_canvas, XtNdestroyNotify, (XtCallbackProc)Canvas_DestroyCallback, gw) ;
	
	/* 先にミニバッファの情報を渡しておく。realize してから入れると危険。*/
	w->onthespotWin.minibuffer_popup  = minibuffer_popup ;
	w->onthespotWin.minibuffer_canvas = minibuffer_canvas ;
	
	/* 取り敢えず実体を持たせる…。XtPopDown とかして大丈夫なのかなあ。*/
	XtRealizeWidget (minibuffer_popup) ;
	XtRealizeWidget (minibuffer_canvas) ;

	minibuffer_popup->core.border_width = 0 ;
	/* 親にリサイズ送っている？ */
	(void) XtMakeResizeRequest (
		(Widget)minibuffer_popup,
		(Dimension)winwidth,  (Dimension)winheight,
		&minibuffer_popup->core.width,
		&minibuffer_popup->core.height) ;
	
	/* ウィンドウのリサイズその他の設定。*/
	sizehints.win_gravity	= NorthWestGravity ;
	sizehints.base_width	= 0 ; /*minibuffer_popup->core.border_width * 2 ;*/
	sizehints.base_height	= 0 ; /*minibuffer_popup->core.border_width * 2 ;*/
	sizehints.width			= sizehints.base_width + winwidth ;
	sizehints.height		= sizehints.base_height + winheight ;
	sizehints.width_inc		= 1 ;  /* 可変長フォントを想定すると最小の増分
								 * が指定できない。*/
	sizehints.height_inc	= font_height ;
	sizehints.min_width		= sizehints.base_width ;
	sizehints.min_height	= sizehints.base_height + winheight ;
	/* 最小の大きさはあっても最大の大きさは無い…ようにしているみたいだ、
	 * mule は…だから、それにあわせること。(minibuffer のね) */
	sizehints.flags			= (PBaseSize | PMinSize | PResizeInc | USSize | PWinGravity) ;
	/* Window Manager にヒントを送っている。*/
	XSetWMNormalHints (XtDisplay (gw), XtWindow (minibuffer_popup), &sizehints) ;
	/*XFlush (XtDisplay (gw)) ;*/
	return ;
}

static void
OnWin_CreateMinibuffer (
	register Widget		gw)
{
	register OnthespotWinWidget w =  (OnthespotWinWidget)gw ;

	w->onthespotWin.minibuffer_win		= None ;
	w->onthespotWin.minibuffer_ofstx	= 0 ;
	OnWin_RealizeMinibuffer (gw) ;
	if (w->onthespotWin.m_fInputFocus) {
		XtSetKeyboardFocus (w->onthespotWin.minibuffer_popup, gw) ;
		XtSetKeyboardFocus (w->onthespotWin.minibuffer_canvas, gw) ;
	}
	return ;
}

/*
 * Widget を実体化させる時に呼ばれる関数。
 */
static void OnWin_Realize (
	register Widget					gw,
	register XtValueMask*			valueMask,
	register XSetWindowAttributes*	attrs)
{
	register OnthespotWinWidget	w		= (OnthespotWinWidget)gw ;
	register CoreWidgetClass	super	= (CoreWidgetClass)XtClass (gw)->core_class.superclass ;

	/* 先に適切なウィンドウを用意させておく。*/
	(*super->core_class.realize) (gw, valueMask, attrs) ;

	/* 変換クライアントが存在しないもしくは、フォントが腐っていると強制
	 * 終了する。*/
	if (w->onthespotWin.client_window == None){
		XtDestroyWidget (gw) ;
		return ;
	}

	if (XtHasCallbacks (gw, XtNfixNotify) != XtCallbackHasSome) 
		XtAddCallback (gw, XtNfixNotify, OnWin_fixcallback, NULL) ;

	/* Minibuffer を作成する。*/
	OnWin_CreateMinibuffer (gw) ;
	OnWin_CreateMinibufferGCs (gw) ;
	//OnWin_ReconfigureColor (gw, CAForegroundPixel | CABackgroundPixel | CAColormap) ;

	OnWin_popup (gw) ;
	return ;
}

/*
 * 全てのイベントを受け付けないようにする関数。
 *---
 * 備考：Destroy する時に呼んで下さい。
 */
static void
OnWin_IgnoreAllWindowEvent (
	register Widget		gw)
{
	register OnthespotWinWidget	w			= (OnthespotWinWidget)gw ;
	register Display*			pDisplay	= XtDisplay(gw) ;

	XSafeSelectInput (pDisplay, XtWindow (w->onthespotWin.minibuffer_popup),  NoEventMask) ;
    XSafeSelectInput (pDisplay, XtWindow (w->onthespotWin.minibuffer_canvas), NoEventMask) ;
	XSafeSelectInput (pDisplay, XtWindow (gw), NoEventMask) ;
	/* Event Queue をフラッシュしておく。*/
	XSafeFlush (pDisplay) ;
	return ;
}

/*
 * SIW に XtDestroyWidget をかけた時に呼び出される関数。
 *-----
 * SIW の終了処理一揃えが入っている。GC を解放してから、malloc してい
 * たメモリを解放している。
 */
static void
OnWin_Destroy (
	register Widget		gw)
{
	register OnthespotWinWidget		w	=  (OnthespotWinWidget)gw ;
	register struct SKKInputNode*	node ;
	register struct SKKInputNode*	pNode ;

	OnWin_popdown (gw) ;

	/* Destroy した以上、以下のウィンドウのイベントは全部無視する。*/
	OnWin_IgnoreAllWindowEvent (gw) ;
	OnWin_ReleaseMinibufferGCs (gw) ;
	OnWin_FreeFontSet (gw) ;
	
	/*
	 * ヒストリを親へと返す。
	 */
	if (w->onthespotWin.historyAttribute != NULL){
		/* ヒストリについて親に返します。*/
		w->onthespotWin.historyAttribute->history_start =
			w->onthespotWin.buffer.hist_start ;
		w->onthespotWin.historyAttribute->history_end =
			w->onthespotWin.buffer.hist_end ;
		/* その場変換モードの状況について親へと返す。*/
		w->onthespotWin.historyAttribute->overthespot_like_input =
			w->onthespotWin.buffer.overthespot_like_input ;
		/* まあ…その仮名モードの状況を親へと返します。*/
		if (w->onthespotWin.buffer.topbuffer != NULL){
			w->onthespotWin.historyAttribute->j_mode =
				w->onthespotWin.buffer.topbuffer->j_mode ;
			w->onthespotWin.historyAttribute->j_zenkaku =
				w->onthespotWin.buffer.topbuffer->j_zenkaku ;
			w->onthespotWin.historyAttribute->j_katakana_mode =
				w->onthespotWin.buffer.topbuffer->j_katakana_mode ;
		}
	}
	/*
	 * バッファを全て解放しておく。
	 */
	node =  (w->onthespotWin.buffer).lastbuffer ;
	while (node != NULL){
		pNode = node->parentbuffer ;
		free_Minibuffer (gw, & (w->onthespotWin.buffer), node) ;
		node  = pNode ;
	}
	XtCallCallbacks (gw, XtNendNotify, w->onthespotWin.historyAttribute) ;
	w->onthespotWin.historyAttribute = NULL ;
	return ;
}

/*
 * あれやこれやとクライアントからのメッセージを見て、ウィジェットを再
 * 設定する関数。
 *----
 * クライアントウィンドウの移動を取れるのだが、クライアントウィンドウ
 * が lower したり、ただ raise しただけだと、どうしようも無いような気
 * がする…。どうにか戦う手段を考えないといけないのだけれども…。
 */
static int
OnWin_ReconfigureWindows (
	register Widget		gw)
{
	register OnthespotWinWidget w =  (OnthespotWinWidget)gw ;

	if (w->onthespotWin.minibuffer_probe &&
		w->onthespotWin.minibuffer_popup != NULL){
		XRaiseWindow (XtDisplay (gw), XtWindow (w->onthespotWin.minibuffer_popup)) ;
	}
	/* Spot Location の変化により文字を表示しているキャンバスを移動させ */
	/* なければならない。この処理を忘れると特に C-h で変換動作中に編集外 */
	/* の文字を消去した時にウィンドウが取り残されることになる。*/
	OnWin_RedrawScreen (gw) ;
	w->onthespotWin.camsg = NULL ;
	return	True ;
}

/*
 * Minibuffer の大きさを変更した後、modeshell の大きさを変更する関数。
 *---
 * 例えばフォントサイズが変更された場合には Minibuffer の大きさを変更
 * する必要がありますね？ また、modeshell の大きさも変更する必要があり
 * ますね？ 
 */
static void
OnWin_ResizeMinibufferAndModeshell (
	register Widget		gw)
{
	register OnthespotWinWidget w =  (OnthespotWinWidget)gw ;
	XSizeHints sizehints ;

	/* modeshell の場所はまあ、後で何とかするでしょうね。*/
	if (w->onthespotWin.change_minibuffer_font){
		if (w->onthespotWin.minibuf_width != 
			w->onthespotWin.minibuffer_popup->core.width ||
			w->onthespotWin.font_height !=
			w->onthespotWin.minibuffer_popup->core.height){
			/* core width, height を変更しておく。*/
			w->onthespotWin.minibuffer_canvas->core.width = 
				w->onthespotWin.minibuffer_popup->core.width = 
				w->onthespotWin.minibuf_width ;
			w->onthespotWin.minibuffer_canvas->core.height =
				w->onthespotWin.minibuffer_popup->core.height =
				w->onthespotWin.font_height ;
			/* Window の大きさを変更する。*/
			XtResizeWindow (w->onthespotWin.minibuffer_popup) ;
			XtResizeWindow (w->onthespotWin.minibuffer_canvas) ;
			/* ミニバッファのウィンドウマネージャー属性を修正する。*/
			sizehints.base_width  = 
				w->onthespotWin.minibuffer_popup->core.border_width * 2 ;
			sizehints.base_height = 
				w->onthespotWin.minibuffer_popup->core.border_width * 2 ;
			sizehints.width_inc  = 1 ;
			sizehints.height_inc = w->onthespotWin.font_height ;
			sizehints.min_width  = sizehints.base_width ;
			sizehints.min_height = w->onthespotWin.font_height +
				sizehints.base_height ;
			sizehints.flags =  (PBaseSize | PMinSize | PResizeInc) ;
			XChangeWMNormalHints
				(XtDisplay (gw),
				 XtWindow (w->onthespotWin.minibuffer_popup),
				 &sizehints) ;
		}
	} else {
		if (w->onthespotWin.minibuf_width != 
			w->onthespotWin.minibuffer_popup->core.width ||
			w->onthespotWin.mfont_height !=
			w->onthespotWin.minibuffer_popup->core.height){
			/* core width, height を変更しておく。*/
			w->onthespotWin.minibuffer_canvas->core.width = 
				w->onthespotWin.minibuffer_popup->core.width = 
				w->onthespotWin.minibuf_width ;
			w->onthespotWin.minibuffer_canvas->core.height =
				w->onthespotWin.minibuffer_popup->core.height =
				w->onthespotWin.mfont_height ;
			/* Window の大きさを変更する。*/
			XtResizeWindow (w->onthespotWin.minibuffer_popup) ;
		}
	}
	return ;
}

/*
 * ウィジェット間のメッセージを受けとる関数。
 */
static Boolean
OnWin_SetValues (
	register Widget			current,
	register Widget			request,
	register Widget			new,
	register ArgList		args,
	register Cardinal*		num_args)
{
	register OnthespotWinWidget		curw = (OnthespotWinWidget)current ;
	register OnthespotWinWidget		reqw = (OnthespotWinWidget)request ;
	register OnthespotWinWidget		neww = (OnthespotWinWidget)new ;
	register struct ConvAttrsMesg*	camsg ;

	/* 辞書が修正されていたら、書き直しを実行する。*/
	if (curw->onthespotWin.buffer.jisyo_dirty !=
		reqw->onthespotWin.buffer.jisyo_dirty){
		neww->onthespotWin.buffer.jisyo_dirty =
			reqw->onthespotWin.buffer.jisyo_dirty ;
		if (neww->onthespotWin.modeshell_probe) {
			/*	modeshell の update? */
		}
		return False ;
	}
	/* 変換属性の修正要求が来た場合と見付けたり。*/
	if (reqw->onthespotWin.camsg != NULL){
		int	ret ;
		camsg = reqw->onthespotWin.camsg ;
		reqw->onthespotWin.camsg = neww->onthespotWin.camsg = 
			curw->onthespotWin.camsg = NULL ;
		
		ret = OnWin_ChangeAttributes (new, camsg->mask, &camsg->value) ;
		/* 変更の影響があって、しかも realize していた場合には…修正する。*/
		if (XtIsRealized (new) && ret)
			OnWin_ReconfigureWindows (new) ;
		return ret ;
	}
	/* ミニバッファを消去したいという要望を受けた時の処理を行う。*/
	if (reqw->onthespotWin.clearMinibuffer){
		if (curw->onthespotWin.minibuffer_probe){
			XtPopdown (curw->onthespotWin.minibuffer_popup) ;
			curw->onthespotWin.minibuffer_probe =
				reqw->onthespotWin.minibuffer_probe =
				neww->onthespotWin.minibuffer_probe = False ;
		}
		reqw->onthespotWin.clearMinibuffer =
			neww->onthespotWin.clearMinibuffer = 
			curw->onthespotWin.clearMinibuffer = False ;
		return	FALSE ;
	}
	if (reqw->onthespotWin.conversion_set_focus){
		reqw->onthespotWin.conversion_set_focus = 
			neww->onthespotWin.conversion_set_focus = 
			curw->onthespotWin.conversion_set_focus = False ;
		if (!neww->onthespotWin.modeshell_probe){
			neww->onthespotWin.modeshell_probe = True ;
		}
		/* mini-buffer を表示する。もし必要ならば…であるが。*/
		OnWin_ConfigureMinibuffer (new) ;
		return FALSE ;
	}
	if (reqw->onthespotWin.conversion_unset_focus){
		reqw->onthespotWin.conversion_unset_focus = 
			neww->onthespotWin.conversion_unset_focus = 
			curw->onthespotWin.conversion_unset_focus = False ;
		if (neww->onthespotWin.modeshell_probe){
			neww->onthespotWin.modeshell_probe = False ;
		}
		return FALSE ;
	}
	return	FALSE ;
}

static void
OnWin_popup (
	register Widget	gw)
{
	register OnthespotWinWidget	wgThis	= (OnthespotWinWidget) gw ;

	if (wgThis->onthespotWin.m_fActive) 
		return ;

	if (wgThis->onthespotWin.m_lstCbkPreeditStart != NULL &&
		XtHasCallbacks (gw, XtNpreeditStartCallback) == XtCallbackHasSome &&
		!wgThis->onthespotWin.m_fPreeditActive) {
		XtCallCallbacks (gw, XtNpreeditStartCallback, 0) ;
		wgThis->onthespotWin.m_fPreeditActive	= True ;
	}
	if (wgThis->onthespotWin.m_lstCbkStatusStart != NULL &&
		XtHasCallbacks (gw, XtNstatusStartCallback) == XtCallbackHasSome) {
		XtCallCallbacks (gw, XtNstatusStartCallback, 0) ;
		Modeshell_Display (gw) ;
	}
	wgThis->onthespotWin.m_fActive	= True ;
	return ;
}

static void
OnWin_popdown (
	register Widget	gw)
{
	register OnthespotWinWidget	wgThis	= (OnthespotWinWidget) gw ;

	if (!wgThis->onthespotWin.m_fActive) 
		return ;

	OnWin_Clear (gw) ;
	if (wgThis->onthespotWin.m_lstCbkPreeditDone != NULL &&
		XtHasCallbacks (gw, XtNpreeditDoneCallback) == XtCallbackHasSome &&
		wgThis->onthespotWin.m_fPreeditActive) {
		XtCallCallbacks (gw, XtNpreeditDoneCallback, 0) ;
	}
	if (wgThis->onthespotWin.m_lstCbkStatusDone != NULL &&
		XtHasCallbacks (gw, XtNstatusDoneCallback) == XtCallbackHasSome) {
		Modeshell_Clear (gw) ;
		XtCallCallbacks (gw, XtNstatusDoneCallback, 0) ;
	}
	wgThis->onthespotWin.m_fActive	= False ;
	return ;
}

/*
 * 変換クライアントからの「変換属性の修正要求」をさばく関数。
 */
static int
OnWin_ChangeAttributes (
	register Widget				gw,
	register unsigned long		valuemask,
	register struct ConvAttrs*	values)
{
	register OnthespotWinWidget w   =  (OnthespotWinWidget)gw ;
	register int ret = False, rec_col ;

	rec_col = False ;
	/* カラーマップの変更要求が来ていたら、それを受ける。*/
	if ((valuemask & CAColormap) &&
		w->onthespotWin.colormap != values->colormap){
		w->onthespotWin.colormap = values->colormap ;
#if defined(DEBUG)
		fprintf (stderr, "(OTSW)Change colormap.\n") ;
#endif
		rec_col = True ;
	}
	/* フォアグラウンドカラー及びバックグラウンドカラーの変更要求が来て *
	 * いたら、それを受ける…。*/
	if ((valuemask & CAForegroundPixel) &&
		w->onthespotWin.oforeground != values->foreground){
#if defined(DEBUG)
		fprintf (stderr, "(OTSW)Change foreground and background colors.\n") ;
#endif
		w->onthespotWin.oforeground = values->foreground ;
		rec_col = True ;
	}
	if ((valuemask & CABackgroundPixel) &&
		w->onthespotWin.obackground != values->background) {
		w->onthespotWin.obackground = values->background ;
		rec_col = True ;
	}
	/* フォント情報の修正があった場合の処理。*/
	if (valuemask & CAFonts){
		/* フォント情報を更新する。この時クライアント側のフォントの情報に
		 * 全て合わせるものとする。例え、クライアントが補助漢字フォントを
		 * 指定してくれなくてデフォルトのフォントを使うことになり、そのフォ
		 * ントの高さが合わなくても…。(見栄えのため) */
		if (fontMgr_GetFontSetInfo (values->fontset,
									&w->onthespotWin.font_height,
									&w->onthespotWin.font_ascent)){
			/* フォントセットをコピーする。*/
			fontMgr_CopyFontSet	(XtDisplay (gw), w->onthespotWin.fontset, values->fontset) ;
			/* ミニバッファとモードシェルの大きさを修正する。*/
			if (XtIsRealized (gw))
				OnWin_ResizeMinibufferAndModeshell (gw) ;
			ret = True ;
		}
	}
	/* フォントの高さに関する制約が送られて来ている場合には…。*/
	if (valuemask & CALineSpacing){
		if (values->linespacing > 0){
			w->onthespotWin.font_height = values->linespacing ;
			ret = True ;
		}
	}
	return ret ;
}

/*
 * キーが押されたというイベントの処理を行う関数。
 *----
 * キーが離されたという情報は入手不可能な場合があるので、押されたとい
 * う情報だけで上手く動作するように作らなければならない。
 */
static void
KeyDownEventHandler (
	register Widget		gw,
	register XEvent*	xevent,
	register String*	params,
	register Cardinal*	num_params)
{
	register OnthespotWinWidget w =  (OnthespotWinWidget)gw ;

#ifdef DEBUG
	fprintf (stderr, "[XEvent] Type(%d), Serial(%ld), Window(%ld)\n", 
			 xevent->type, xevent->xany.serial, xevent->xany.window) ;
#endif
	if (commonKeyEventHandler (gw, xevent, & (w->onthespotWin.buffer))) {
		OnWin_RedrawScreen (gw) ;
	}
	return ;
}

/*
 * フォーカスが合わされた時の処理を行う関数。
 */
static void
FocusEventHandler (
	register Widget		gw,
	register XEvent*	xevent,
	register String*	params,
	register Cardinal*	num_params)
{
	return ;
}

static void
OnWin_Clear (
	register Widget	gw)
{
	register OnthespotWinWidget	wgThis		= (OnthespotWinWidget) gw ;
	TOnTheSpotDrawArg			arg ;

	if (wgThis->onthespotWin.m_fPreeditActive) {
		if (wgThis->onthespotWin.m_lstCbkPreeditDraw != NULL &&
			XtHasCallbacks (gw, XtNpreeditDrawCallback) == XtCallbackHasSome) {
			arg.m_nChgFirst		= 0 ;
			arg.m_nChgLength	= myCharStrlen (wgThis->onthespotWin.m_strPreeditText) ;
			arg.m_pText			= NULL ;
			arg.m_nText			= 0 ;
			arg.m_pAttribute	= NULL ;
			arg.m_nAttribute	= 0 ;
			arg.m_nCaret		= 0 ;
			XtCallCallbacks (gw, XtNpreeditDrawCallback, &arg) ;
		}
		if (wgThis->onthespotWin.m_lstCbkPreeditDone != NULL &&
			XtHasCallbacks (gw, XtNpreeditDoneCallback) == XtCallbackHasSome) {
			XtCallCallbacks (gw, XtNpreeditDoneCallback, 0) ;
		}
		wgThis->onthespotWin.m_fPreeditActive	= False ;
	}
	wgThis->onthespotWin.m_nPreeditCaret	= 0 ;
	MYCHAR_SET_END_OF_STRING (wgThis->onthespotWin.m_strPreeditText [0]) ;
	return ;
}

static void
OnWin_Display (
	register Widget	gw)
{
	register OnthespotWinWidget	wgThis		= (OnthespotWinWidget) gw ;
	register struct SKKInputNode*	node ;
	register int					nDrawLen ;
	register int					nCaret ;
	XIMFeedback						rfeedbacks [TEXTBUFSIZE + 1] ;
	register XIMFeedback*			pFeedback ;
	TOnTheSpotDrawArg				arg ;
#if 0
	register int					nDrawStart, nUpdate ;
	register struct myChar*			pCurText ;
	register struct myChar*			pPrevText ;

	node		= wgThis->onthespotWin.buffer.topbuffer ;
	pCurText	= node->textbuffer + node->cur_pos_top ;
	pPrevText	= wgThis->onthespotWin.m_strPreeditText ;
	while ((pPrevText->chara   == pCurText->chara  &&
			(pPrevText->charset == pCurText->charset ||
			 (IS_ASCII_CHARA (*pPrevText) && IS_ASCII_CHARA (*pCurText)))) &&
		   !IS_END_OF_STRING (*pCurText)) {
		pPrevText	++ ;
		pCurText	++ ;
	}
	nDrawStart	= (pCurText - node->textbuffer) - node->cur_pos_top ;
	while (! IS_END_OF_STRING (*pCurText)) 
		pCurText	++ ;
	nDrawLen	= (pCurText - node->textbuffer) - node->cur_pos_top ;
		
	nCaret	= node->cur_pos - node->cur_pos_top ;
	if (wgThis->onthespotWin.m_nPreeditCaret != nCaret) {
		if (nDrawStart > nCaret)
			nDrawStart	= nCaret ;
	}
	nUpdate	= nDrawLen - nDrawStart ;
#else
	node		= wgThis->onthespotWin.buffer.topbuffer ;

	nDrawLen	= myCharStrlen (node->textbuffer + node->cur_pos_top) ;
	nCaret		= nDrawLen ;
#endif
	//if (nUpdate <= 0) {
	if (nDrawLen <= 0) {
		OnWin_Clear (gw) ;
		return ;
	}
	if (! wgThis->onthespotWin.m_fPreeditActive) {
		if (wgThis->onthespotWin.m_lstCbkPreeditStart != NULL &&
			XtHasCallbacks (gw, XtNpreeditStartCallback) == XtCallbackHasSome)
			XtCallCallbacks (gw, XtNpreeditStartCallback, 0) ;
		wgThis->onthespotWin.m_fPreeditActive	= True ;
	}

	if (wgThis->onthespotWin.m_lstCbkPreeditDraw != NULL &&
		XtHasCallbacks (gw, XtNpreeditDrawCallback) == XtCallbackHasSome) {
		register int	i ;
		
		pFeedback	= rfeedbacks ;
		for (i = node->cur_pos_top ; i < (node->cur_pos_top + nDrawLen) ; i ++) {
			if (node->cur_pos == i) {
				*pFeedback ++	= XIMReverse ;
			} else {
				*pFeedback ++	= XIMUnderline ;
			}
		}
		*pFeedback			= XIMUnderline ;
		arg.m_nCaret		= nDrawLen ;
			
		/*	PreeditDraw Callback の時に渡す String は ChgFirst から
		 *	ChgLength 分だけの「変更された display される string」な
		 *	のか、それとも「変更されてない部分も含めた display される
		 *	string」なのかが分からない。
		 *
		 *	これを回避する方法は、「全部書き直す」こと。
		 *(※)
		 *	KDE3.0 では「変更された部分だけ」を Text に入れるように
		 *	実装している。
		 */
		arg.m_nChgFirst		= 0 ;
		arg.m_nChgLength	= myCharStrlen (wgThis->onthespotWin.m_strPreeditText) ;
		arg.m_pText			= node->textbuffer + node->cur_pos_top ;
		arg.m_nText			= nDrawLen ;
		arg.m_pAttribute	= rfeedbacks ;
		arg.m_nAttribute	= nDrawLen + 1 ;
		XtCallCallbacks (gw, XtNpreeditDrawCallback, &arg) ;
	}
	memcpy (wgThis->onthespotWin.m_strPreeditText, node->textbuffer + node->cur_pos_top, (sizeof (struct myChar)) * nDrawLen) ;
	MYCHAR_SET_END_OF_STRING (wgThis->onthespotWin.m_strPreeditText [nDrawLen]) ;
	wgThis->onthespotWin.m_nPreeditCaret	= nCaret ;
	return ;
}

/*
 * skkinput の画面をいちいち全部書き直す関数。
 *-----
 * 画面の大きさの変更などが行われた時にはこちらの関数が呼ばれることに
 * なる。
 */
static void
OnWin_RedrawScreen (
	register Widget	 gw)
{
	Modeshell_Display (gw) ;
	OnWin_Display (gw) ;
	OnWin_ConfigureMinibuffer (gw) ;
	return ;
}

/*
 * ミニバッファウィンドウの配置、大きさの設定を行う関数。
 *----
 * 大きさは実は設定してません。最初に設定したきりです。画面の内にミニ
 * バッファ窓を何処に置いたら良いのかな…と判断するに使うわけです。
 */
static void
OnWin_ConfigureMinibuffer (
	register Widget		gw)
{
	register OnthespotWinWidget		w		= (OnthespotWinWidget)gw ;
	register struct SKKInputNode*	node	= w->onthespotWin.buffer.topbuffer ;
	register struct SKKInputNode*	mNode	= w->onthespotWin.buffer.lastbuffer ;
	register Window	win ;
	
	if (mNode == node){
		/* 表示すべきテキストが何も無かった場合には。*/
		if (IS_END_OF_STRING (node->mtextbuffer[ 0 ])){
			if (w->onthespotWin.minibuffer_probe){
				w->onthespotWin.minibuffer_probe = False ;
				XtPopdown (w->onthespotWin.minibuffer_popup) ;
			}
			return ;
		}
	}
	if (!w->onthespotWin.minibuffer_probe){
		/* 指定された位置にミニバッファを移動させる。*/
		//OnWin_ConfigureMinibufferPosition (gw, &x, &y) ;
		//XtMoveWidget (w->onthespotWin.minibuffer_popup, x, y) ;
		/* Popup する。*/
		XtPopup (w->onthespotWin.minibuffer_popup, XtGrabNone) ;
	}
	win = XtWindow (w->onthespotWin.minibuffer_canvas) ;
	w->onthespotWin.minibuffer_probe = True ;
	/* キャンバスを書き直すように要求を出す。*/
	Minibuffer_Redisplay (gw, win) ;
	return ;
}    

static void
Minibuffer_Redisplay (
	register Widget		gw,
	register Window		win)
{
	register OnthespotWinWidget		w			=  (OnthespotWinWidget)gw ;
	register Display*				pDisplay	= XtDisplay (gw) ;
	register struct SKKInputNode*	mNode ;
	register struct SKKInputNode*	node		= w->onthespotWin.buffer.topbuffer ;
	register struct skkinputManagedFont**	fontset ;
	register int	fontheight, fontascent ;
	int				toppos ;
	register GC		gc, rgc ;

	if (!w->onthespotWin.minibuffer_probe)
		return ;

	gc  		= w->onthespotWin.minibuf_gc ;
	rgc			= w->onthespotWin.minibuf_rgc ;
	XRaiseWindow (XtDisplay (gw), win) ;
    fontset		= w->onthespotWin.minibuf_fontset ;
    fontascent	= w->onthespotWin.mfont_ascent ;
    fontheight	= w->onthespotWin.mfont_height ;
	XClearWindow (XtDisplay (gw), win) ;

	/* mini-buffer を表示する。*/
	mNode = w->onthespotWin.buffer.lastbuffer ;

	if (mNode == node){
		/* 表示すべきテキストが何も無かった場合には。*/
		if (IS_END_OF_STRING (node->mtextbuffer [0]))
			return ;

		skkwin_jputstring (pDisplay, win, fontset, gc, 0, fontascent, node->mtextbuffer) ;
	} else {
		if (!IS_END_OF_STRING (mNode->mtextbuffer [0])){
			skkwin_jputstring (pDisplay, win, fontset, gc, 0, fontascent, mNode->mtextbuffer) ;
		} else {
			struct myChar*	toptext ;
			register int			width ;
			XWindowAttributes xwa ;

			/* ここで横幅が問題になるから…横幅を抜き出しておく。*/
			XGetWindowAttributes (pDisplay, win, &xwa) ;
			width	= xwa.width ;

			/* Window の buffer に文字列を表示する。*/
			OTSW_CalcTopPositionOfBuffer (
				fontset, mNode->textbuffer, 0, mNode->cur_pos, width, &toptext, &toppos) ;
			OTSW_FullDrawTopBufferTopLine (
				pDisplay, win, fontset, gc, rgc, 
				toptext, toppos, fontascent, fontheight, width,
				!IS_END_OF_STRING (mNode->textbuffer [mNode->cur_pos]),
				w->onthespotWin.cursor_width,
				mNode->cur_pos, mNode->cur_exist, 
				True) ;
		}
	}
	XFlush (pDisplay) ;
	return ;
}

/*
 * この関数は現在の状況下での再描画しかしません。popup/popdown などは
 * 親ががんばってしてくれることにします…問題アリかなあ？ でも、状況の
 * 変化を見切って動作を与えるのは親(つまり onthespotWinWidget)なのだ
 * から、子供に責任とらせるってのは…。
 */
static void
Minibuffer_RedisplayCallback (
	register Widget		gw,
	register caddr_t	client,
	register caddr_t	caller)
{
	register Widget w =  (Widget)client ;
	Minibuffer_Redisplay (w, XtWindow (gw)) ;
	return ;
}

static void
Modeshell_Clear (
	register Widget		gw)
{
	register OnthespotWinWidget w =  (OnthespotWinWidget)gw ;
	TOnTheSpotDrawArg		arg ;

	if (w->onthespotWin.m_lstCbkStatusDraw == NULL ||
		XtHasCallbacks (gw, XtNstatusDrawCallback) != XtCallbackHasSome) 
		return ;

	arg.m_pText	= NULL ;
	arg.m_nText	= 0 ;
	XtCallCallbacks (gw, XtNstatusDrawCallback, &arg) ;
	MYCHAR_SET_END_OF_STRING (w->onthespotWin.m_strModeText [0]) ;
	w->onthespotWin.m_nModeTextLen	= 0 ;
	return ;
}

/*
 * modeshell window にモードを表示をする関数。
 */
static void
Modeshell_Display (
	register Widget		gw)
{
	register OnthespotWinWidget w =  (OnthespotWinWidget)gw ;
	struct myChar	sstrCurModeText [4 + 2 + 1] ; /* magic number ... */
	register int	nText ;

	if (w->onthespotWin.m_lstCbkStatusDraw == NULL ||
		XtHasCallbacks (gw, XtNstatusDrawCallback) != XtCallbackHasSome) 
		return ;

	nText	= GetModeLineText (w->onthespotWin.buffer.topbuffer,
							   w->onthespotWin.buffer.jisyo_dirty,
							   w->onthespotWin.buffer.overthespot_like_input,
							   NULL) ;
	/* fatal error */
	if (nText >= sizeof (sstrCurModeText) / sizeof (sstrCurModeText [0])) {
		/* Too long modeshell string. So, I ignore. */
		return ;
	}
	(void) GetModeLineText (w->onthespotWin.buffer.topbuffer,
							w->onthespotWin.buffer.jisyo_dirty,
							w->onthespotWin.buffer.overthespot_like_input,
							sstrCurModeText) ;

	if (w->onthespotWin.m_nModeTextLen != nText ||
		! memcmp (sstrCurModeText, w->onthespotWin.m_strModeText, sizeof (struct myChar) * nText)) {
		TOnTheSpotDrawArg		arg ;
		arg.m_pText	= sstrCurModeText ;
		arg.m_nText	= nText ;
		XtCallCallbacks (gw, XtNstatusDrawCallback, &arg) ;
	}
	memcpy (w->onthespotWin.m_strModeText, sstrCurModeText, sizeof (struct myChar) * nText) ;
	w->onthespotWin.m_nModeTextLen	= nText ;
	return ;
}

/*
 * Window Manager の close button をクリックした時に呼ばれるコールバッ
 * ク関数。
 */
static void
OnWin_wmMessageCloseCallback (
	register Widget		gw,
	register caddr_t	client,
	register caddr_t	caller)
{
	register OnthespotWinWidget w =  (OnthespotWinWidget)client ;

	force_keyboard_quit ((Widget)w, & (w->onthespotWin.buffer)) ;
	return ;
}

static void
OnWin_wmShellDestroyCallback (
	register Widget		gw,
	register caddr_t	client,
	register caddr_t	caller)
{
	/* 全てのコールバック関数を破棄しておく。*/
	XtRemoveAllCallbacks (gw, XtNwmcloseNotify) ;
	XtRemoveAllCallbacks (gw, XtNdestroyNotify) ;
	return ;
}

/*
 * Canvas Widget を壊す時に呼び出されるコールバック関数。
 */
static void
Canvas_DestroyCallback (
	register Widget		gw,
	register caddr_t	client,
	register caddr_t	caller)
{
	XtRemoveAllCallbacks (gw, XtNredrawNotify) ;
	XtRemoveAllCallbacks (gw, XtNdestroyNotify) ;
	return ;
}

static void
OnWin_fixcallback (
	register Widget		gw,
	register XtPointer	client,
	register XtPointer	caller)
{
	register OnthespotWinWidget wgThis =  (OnthespotWinWidget)gw ;
	TOnTheSpotDrawArg			arg ;
	register Boolean			fClear ;

	fClear	= wgThis->onthespotWin.m_fPreeditActive ;
	if (fClear) {
 		arg.m_nCaret		= 0 ;
		arg.m_nChgFirst		= 0 ;
		arg.m_nChgLength	= myCharStrlen (wgThis->onthespotWin.m_strPreeditText) ;
		arg.m_pText			= NULL ;
		arg.m_nText			= 0 ;
		arg.m_pAttribute	= NULL ;
		arg.m_nAttribute	= 0 ;
		XtCallCallbacks (gw, XtNpreeditDrawCallback, &arg) ;
 		MYCHAR_SET_END_OF_STRING (wgThis->onthespotWin.m_strPreeditText [0]) ;
 		wgThis->onthespotWin.m_nPreeditCaret	= 0 ;
	}
	XtCallCallbacks (gw, XtNtextNotify, caller) ;

	if (fClear) 
		OnWin_Display (gw) ;
	return ;
}

