/* # skkinput (Simple Kana-Kanji Input)
 *
 * This file is part of skkinput.
 * Copyright (C) 2002
 * Takashi SAKAMOTO (PXG01715@nifty.ne.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 <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <sys/time.h>
#include "XIMInputContextP.h"
#include "XIMClient.h"
#include "XIMData.h" 
#include "commondef.h"
#include "OverWin.h"
#include "OffWin.h"
#include "OnWin.h"
#include "SeparateWin.h"
#include "MyDispatch.h"
#include "resrcs.h"
#include "FontMgr.h"
#include "HistMgr.h"

#define	DEFAULT_XIM_PREEDIT_LINESPACING		(14)
#define	DEFAULT_XIM_STATUS_LINESPACING		(14)

static	Boolean	ximInputContext_createFrame			(XIMInputContext*) ;
static	void	ximInputContext_onPreeditStart		(Widget, XtPointer, XtPointer) ;
static	void	ximInputContext_onPreeditDraw		(Widget, XtPointer, XtPointer) ;
static	void	ximInputContext_onPreeditCaret		(Widget, XtPointer, XtPointer) ;
static	void	ximInputContext_onPreeditDone		(Widget, XtPointer, XtPointer) ;
static	void	ximInputContext_onStatusStart		(Widget, XtPointer, XtPointer) ;
static	void	ximInputContext_onStatusDraw		(Widget, XtPointer, XtPointer) ;
static	void	ximInputContext_onStatusDone		(Widget, XtPointer, XtPointer) ;

static	void	ximInputContext_onKeyBackNotify 	(Widget, XtPointer, XtPointer) ;
static	void	ximInputContext_onEndNotify		 	(Widget, XtPointer, XtPointer) ;
static	void	ximInputContext_onTextNotify 		(Widget, XtPointer, XtPointer) ;

static	Boolean	ximInputContext_packetToCombinep	(XIMPacket*) ;
static	XIMPacket*	ximInputContext_combineXimCommit(XIMInputContext*, XIMPacket*, XIMPacket*) ;

XIMInputContext*
XIMInputContext_Create (
	register XIMInputMethod*	pInputMethod,
	register int				nID)
{
	register XIMInputContext*	pInputContext ;
	register int				i ;

	pInputContext	= malloc (sizeof (XIMInputContext)) ;
	if (pInputContext == NULL)
		return	NULL ;

	pInputContext->m_pInputMethod		= pInputMethod ;
	pInputContext->m_pNext				= NULL ;
	pInputContext->m_woID				= nID ;
	pInputContext->m_ulAttributeMask	= 0L ;
	pInputContext->m_wgTopFrame			= NULL ;
	pInputContext->m_ulResetState		= XIMInitialState ;
	pInputContext->m_preeditState		= XIMPreeditDisable ;
	pInputContext->m_wndClient			= None ;
	pInputContext->m_wndFocus			= None ;
	pInputContext->m_dwFilterEvents		= 0 ;
	pInputContext->m_uSyncStatus		= 0 ;
	pInputContext->m_dwInputStyle		= XIMStatusNothing | XIMPreeditNothing ;
	pInputContext->m_pNext				= NULL ;
	pInputContext->m_fDestroy			= False ;
	pInputContext->m_fFocus				= False ;
	pInputContext->m_atPStdColormap		= None ;
	pInputContext->m_atSStdColormap		= None ;
	TQueue_Initialize     (&pInputContext->m_quePacketSpool,   sizeof (XIMPacket*)) ;
	TVarbuffer_Initialize (&pInputContext->m_vbufPFontSetName, sizeof (char)) ;
	TVarbuffer_Initialize (&pInputContext->m_vbufSFontSetName, sizeof (char)) ;
	pInputContext->m_ConvAttr.mask		= 0 ;

	/* フォントセットの初期化を行う。*/
	for (i = 0 ; i < NUMBER_OF_CHARSET ; i ++)
		pInputContext->m_fontset [i]	= NULL ;
	pInputContext->m_nFontHeight		= DEFAULT_XIM_PREEDIT_LINESPACING ;

	return	pInputContext ;
}	

void
XIMInputContext_Destroy (
	register XIMInputContext*	pThis)
{
	register XIMPacket**	ppPacket ;
	register int			nPacket ;
	register Widget			gwClient ;

	ppPacket	= TQueue_GetData  (&pThis->m_quePacketSpool) ;
	nPacket		= TQueue_GetUsage (&pThis->m_quePacketSpool) ;
	while (nPacket -- > 0) 
		XIMPacket_Release (*ppPacket ++) ;

	TQueue_Uninitialize     (&pThis->m_quePacketSpool) ;
	TVarbuffer_Uninitialize (&pThis->m_vbufPFontSetName) ;
	TVarbuffer_Uninitialize (&pThis->m_vbufSFontSetName) ;

	gwClient	= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	if (gwClient != NULL) {
		register Display*	pDisplay	= XtDisplay (gwClient) ;
		register int		i ;

		/* フォントを解放する。*/
		for (i = 0 ; i < NUMBER_OF_CHARSET ; i ++){
			fontMgr_FreeFont (pDisplay,  pThis->m_fontset [i]) ;
			pThis->m_fontset [i]	= NULL ;
		}
	}

	if (pThis->m_wgTopFrame != NULL) {
		register Widget	wgFrame	= pThis->m_wgTopFrame ;
		XtRemoveCallback (wgFrame, XtNfixNotify,	 ximInputContext_onTextNotify,   (XtPointer)pThis) ;
		XtRemoveCallback (wgFrame, XtNendNotify,	 ximInputContext_onEndNotify,    (XtPointer)pThis) ;
		XtRemoveCallback (wgFrame, XtNkeybackNotify, ximInputContext_onKeyBackNotify, (XtPointer)pThis) ;

		if (XtIsSubclass (wgFrame, onthespotWinWidgetClass)) {
			XtRemoveAllCallbacks (wgFrame, XtNpreeditStartCallback) ;
			XtRemoveAllCallbacks (wgFrame, XtNpreeditDrawCallback) ;
			XtRemoveAllCallbacks (wgFrame, XtNpreeditCaretCallback) ;
			XtRemoveAllCallbacks (wgFrame, XtNpreeditDoneCallback) ;
			XtRemoveAllCallbacks (wgFrame, XtNstatusStartCallback) ;
			XtRemoveAllCallbacks (wgFrame, XtNstatusDrawCallback) ;
			XtRemoveAllCallbacks (wgFrame, XtNstatusDoneCallback) ;
		}
	}
	pThis->m_wgTopFrame			= NULL ;

	free (pThis) ;
	return ;
}

void
XIMInputContext_SetNext (
	register XIMInputContext*	pThis,
	register XIMInputContext*	pNext)
{
	assert (pThis != NULL) ;
	pThis->m_pNext	= pNext ;
	return ;
}

XIMInputContext*
XIMInputContext_GetNext (
	register XIMInputContext*	pThis)
{
	assert (pThis != NULL) ;
	return	pThis->m_pNext ;
}

int
XIMInputContext_GetID (
	register XIMInputContext*	pThis)
{
	assert (pThis != NULL) ;
	return	pThis->m_woID ;
}

Boolean
XIMInputContext_Alivep (
	register XIMInputContext*	pThis)
{
	assert (pThis != NULL) ;
	return	!pThis->m_fDestroy ;
}

Boolean
XIMInputContext_ForwardEvent (
	register XIMInputContext*	pThis,
	register XEvent*			pXEvent)
{
#if defined (DEBUG)
	fprintf (stderr, "XIMInputContext_ForwardEvent (%p, %p)\n", pThis, pXEvent) ;
#endif

	if (pXEvent->type != KeyPress) 
		return	True ;

	pXEvent->xkey.send_event	= True ;
	XtCallActionProc (pThis->m_wgTopFrame, "KeyDownEventHandler", pXEvent, (String*)NULL, (Cardinal)0) ;
	return	True ;
}

Boolean
XIMInputContext_StartConversion (
	register XIMInputContext*	pThis)
{
	register Widget	wgClient ;

#if defined (DEBUG)
	fprintf (stderr, "XIMInputContext_StartConversion (%p)\n", pThis) ;
#endif

	if (pThis->m_preeditState == XIMPreeditEnable)
		return	True ;

	/*	一番最初の変換動作の場合には Widget を作成する必要がある。
	 */
	if (pThis->m_wgTopFrame == NULL) {
		if (!ximInputContext_createFrame (pThis))
			return	False ;
	}
	pThis->m_preeditState	= XIMPreeditEnable ;
	wgClient	= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	XIMInputContext_Activate (pThis, True) ;
	pThis->m_fFocus	= True ;
	return	True ;
}

Boolean
XIMInputContext_EndConversion (
	register XIMInputContext*	pThis)
{
	register Widget	wgClient ;

#if defined (DEBUG)
	fprintf (stderr, "XIMInputContext_StartConversion (%p)\n", pThis) ;
#endif
	if (pThis->m_preeditState == XIMPreeditDisable)
		return	False ;

	pThis->m_preeditState	= XIMPreeditDisable ;
	XIMInputContext_Activate (pThis, False) ;

	wgClient	= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	//XIMClient_PreeditStateChange (wgClient, pThis->m_pInputMethod, pThis) ;
	return	True ;
}

Boolean
XIMInputContext_ResetConversion (
	register XIMInputContext*	pThis)
{
	return	True ;
}

unsigned
XIMInputContext_GetSyncMode (
	register XIMInputContext*	pThis)
{
	assert (pThis != NULL) ;
	return	pThis->m_uSyncStatus ;
}

void
XIMInputContext_SetSyncMode (
	register XIMInputContext*	pThis,
	register unsigned			uMode)
{
	assert (pThis != NULL) ;
	assert ((uMode & XIMClientSync) || !(pThis->m_uSyncStatus & ~XIMClientSync)) ;
	pThis->m_uSyncStatus	|= uMode ;
	return ;
}

void
XIMInputContext_UnsetSyncMode (
	register XIMInputContext*	pThis,
	register unsigned			uMode)
{
	assert (pThis != NULL) ;

	pThis->m_uSyncStatus	&= ~uMode ;
	return ;
}

Boolean
XIMInputContext_SpoolPacket (
	register XIMInputContext*	pThis,
	XIMPacket*					pPacket)
{
	/*	Spool されている直前の packet が XIM_COMMIT ならば、連結する。*/
	if (ximInputContext_packetToCombinep (pPacket)) {
		register XIMPacket**	ppSpooledPacket ;
		register int			npSpooledPacket ;

		ppSpooledPacket	= TQueue_GetData  (&pThis->m_quePacketSpool) ;
		npSpooledPacket	= TQueue_GetUsage (&pThis->m_quePacketSpool) ;
		if (npSpooledPacket > 0) {
			register XIMPacket*		pLastPacket ;

			pLastPacket	= *(ppSpooledPacket + npSpooledPacket - 1) ;
			if (ximInputContext_packetToCombinep (pLastPacket)) {
				register XIMPacket*	pNewPacket ;
				pNewPacket	= ximInputContext_combineXimCommit (pThis, pLastPacket, pPacket) ;
				if (pNewPacket == NULL)
					return	False ;
				XIMPacket_Release (pLastPacket) ;
				*(ppSpooledPacket + npSpooledPacket - 1)	= pNewPacket ;
				return	True ;
			}
		}
	}

	if (! (TQueue_In (&pThis->m_quePacketSpool, &pPacket, 1)))
		return	False ;
	XIMPacket_AddRef (pPacket) ;
	return	True ;
}

XIMPacket*
XIMInputContext_GetSpooledPacket (
	register XIMInputContext*	pThis)
{
	XIMPacket*		pPacket ;
	register int	nOut ;

	nOut	= TQueue_Out (&pThis->m_quePacketSpool, &pPacket, 1) ;
	if (nOut <= 0)
		return	NULL ;
	return	pPacket ;
}

XIMPacket*
XIMInputContext_LookSpooledPacket (
	register XIMInputContext*	pThis)
{
	register TQueue*	pQueue ;

	assert (pThis != NULL) ;

	pQueue	= &pThis->m_quePacketSpool ;
	if (TQueue_GetUsage (pQueue) <= 0)
		return	NULL ;

	return	TQueue_GetData (pQueue) ;
}

int
XIMInputContext_GetNumberOfSpooledPacket (
	register XIMInputContext*	pThis)
{
	return	TQueue_GetUsage (&pThis->m_quePacketSpool) ;
}

Boolean
XIMInputContext_SetFocus (
	register XIMInputContext*	pThis)
{
	if (pThis->m_preeditState == XIMPreeditDisable)
		return	False ;

#if defined (DEBUG) || 0
	fprintf (stderr, "XIMInputContext_SetFocus (%p, %d)\n",
			 pThis, pThis->m_woID) ;
#endif
	/*	setfocus */
	pThis->m_fFocus	= True ;
	if (pThis->m_wgTopFrame != NULL) 
		XIMInputContext_Activate (pThis, True) ;
	return	True ;
}

Boolean
XIMInputContext_UnsetFocus (
	register XIMInputContext*	pThis)
{
	if (pThis->m_preeditState == XIMPreeditDisable)
		return	False ;

#if defined (DEBUG) || 0
	fprintf (stderr, "XIMInputContext_UnsetFocus (%p, %d)\n",
			 pThis, pThis->m_woID) ;
#endif
	/*	unsetfocus */
	pThis->m_fFocus	= False ;
	if (pThis->m_wgTopFrame != NULL) 
		XIMInputContext_Activate (pThis, False) ;
	return	True ;
}

Boolean
XIMInputContext_SetInputStyle (
	register XIMInputContext*	pThis,
	register XIMStyle			imstyle)
{
#if defined (DEBUG) || 0
	fprintf (stderr, "XIMInputContext_SetInputStyle (%p, %d)\n",
			 pThis, imstyle) ;
#endif
	pThis->m_dwInputStyle		= imstyle ;
	pThis->m_ConvAttr.mask	|= CAInputStyle ;
	return	True ;
}

Boolean
XIMInputContext_SetClientWindow (
	register XIMInputContext*	pThis,
	register Window				wndClient)
{
#if defined (DEBUG) || 0
	fprintf (stderr, "XIMInputContext_SetClientWindow (%p, %x)\n",
			 pThis, wndClient) ;
#endif
	/*	client window は一度しか設定できない。*/
	if (pThis->m_wndClient != None)
		return	False ;
	pThis->m_wndClient	= wndClient ;
	return	True ;
}

Boolean
XIMInputContext_SetFocusWindow (
	register XIMInputContext*	pThis,
	register Window				wndFocus)
{
#if defined (DEBUG) || 0
	fprintf (stderr, "XIMInputContext_SetFocusWindow (%p, %x)\n",
			 pThis, wndFocus) ;
#endif
	if (!(pThis->m_ConvAttr.mask & CAFocusWindow) ||
		pThis->m_ConvAttr.value.focus_window != wndFocus) {
		pThis->m_ConvAttr.value.focus_window  = wndFocus ;

		if (pThis->m_wgTopFrame != NULL) {
			struct ConvAttrsMesg	ca ;
			ca.mask					= CAFocusWindow ;
			ca.value.focus_window	= wndFocus ;
			XtVaSetValues (pThis->m_wgTopFrame, XtNconversionAttribute, &ca, NULL) ;
		}
	}
	pThis->m_ConvAttr.mask	|= CAFocusWindow ;
	return	True ;
}

Boolean
XIMInputContext_SetResetState (
	register XIMInputContext*	pThis,
	register XIMResetState		ulResetState)
{
	if (ulResetState != XIMInitialState && ulResetState != XIMPreserveState)
		return	False ;
	pThis->m_ulResetState	= ulResetState ;
	return	True ;
}

Boolean
XIMInputContext_SetPreeditState (
	register XIMInputContext*	pThis,
	register XIMPreeditState	ulPreeditState)
{
	if (ulPreeditState != XIMPreeditEnable && ulPreeditState != XIMPreeditDisable)
		return	False ;
	if (ulPreeditState != pThis->m_preeditState) {
		Widget	wgClient	= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
		if (ulPreeditState == XIMPreeditEnable) {
			XIMClient_ControlEventFlow (wgClient, pThis->m_pInputMethod, pThis, True) ;
			XIMInputContext_StartConversion (pThis) ;
		} else {
			XIMClient_ControlEventFlow (wgClient, pThis->m_pInputMethod, pThis, False) ;
			XIMInputContext_EndConversion (pThis) ;
		}
	}
	return	True ;
}

XIMStyle
XIMInputContext_GetInputStyle (
	register XIMInputContext*	pThis)
{
	return	pThis->m_dwInputStyle ;
}

Window
XIMInputContext_GetClientWindow (
	register XIMInputContext*	pThis)
{
	return	pThis->m_wndClient ;
}

Window
XIMInputContext_GetFocusWindow (
	register XIMInputContext*	pThis)
{
	return	pThis->m_wndFocus ;
}

CARD32
XIMInputContext_GetFilterEvents (
	register XIMInputContext*	pThis)
{
	return	pThis->m_dwFilterEvents ;
}

XIMResetState
XIMInputContext_GetResetState (
	register XIMInputContext*	pThis)
{
	return	pThis->m_ulResetState ;
}

XIMPreeditState
XIMInputContext_GetPreeditState (
	register XIMInputContext*	pThis)
{
	return	pThis->m_preeditState ;
}

Boolean
XIMInputContext_SetPreeditArea (
	register XIMInputContext*	pThis,
	register const XRectangle*	pRect)
{
#if defined (DEBUG) || 0
	fprintf (stderr, "XIMInputContext[%d]: SetPreeditArea (%d, %d, %d, %d)\n",
			 pThis->m_woID,
			 pRect->x, pRect->y, pRect->width, pRect->height) ;
#endif
#if 1
	if (pRect->width <= 0 || pRect->height <= 0)
		return	False ;
#endif
	if (! (pThis->m_ConvAttr.mask & CAClientArea) ||
		! (pThis->m_ConvAttr.value.client_area.x == pRect->x &&
		   pThis->m_ConvAttr.value.client_area.y == pRect->y &&
		   pThis->m_ConvAttr.value.client_area.width  == pRect->width &&
		   pThis->m_ConvAttr.value.client_area.height == pRect->height)) {
		pThis->m_ConvAttr.mask	|= CAClientArea ;
		pThis->m_ConvAttr.value.client_area	= *pRect ;

		if (pThis->m_wgTopFrame != NULL) {
			struct ConvAttrsMesg	ca ;
			ca.mask					= CAClientArea ;
			ca.value.client_area	= *pRect ;
			XtVaSetValues (pThis->m_wgTopFrame, XtNconversionAttribute, &ca, NULL) ;
		}
	}
	return	True ;
}

Boolean
XIMInputContext_SetPreeditAreaNeeded (
	register XIMInputContext*	pThis,
	register const XRectangle*	pRect)
{
#if defined (DEBUG) || 0
	fprintf (stderr, "XIMInputContext_SetPreeditAreaNeeded (%p, %p)\n",
			 pThis, pRect) ;
#endif
	/*	ClientAreaNeeded が入ると、ClientArea のサイズは
	 *	こちらにひっぱられる。
	 */
	if (! (pThis->m_ConvAttr.mask & CAClientAreaNeeded) ||
		! (pThis->m_rcClientAreaNeeded.x == pRect->x &&
		   pThis->m_rcClientAreaNeeded.y == pRect->y &&
		   pThis->m_rcClientAreaNeeded.width  == pRect->width &&
		   pThis->m_rcClientAreaNeeded.height == pRect->height)) {
		pThis->m_ConvAttr.mask	|= CAClientAreaNeeded ;
		pThis->m_rcClientAreaNeeded	= *pRect ;
	}
	return	True ;
}

Boolean
XIMInputContext_SetSpotLocation (
	register XIMInputContext*	pThis,
	register const XPoint*		pPos)
{
#if defined (DEBUG)
	fprintf (stderr, "XIMInputContext_SetSpotLocation (%p, %d, %d)\n",
			 pThis, pPos->x, pPos->y) ;
#endif
	if (!(pThis->m_ConvAttr.mask & CASpotLocation) ||
		!(pThis->m_ConvAttr.value.spot_x == pPos->x &&
		  pThis->m_ConvAttr.value.spot_y == pPos->y)) {
		if (pThis->m_wgTopFrame != NULL) {
			struct ConvAttrsMesg		ca ;

			ca.mask			= CASpotLocation ;
			ca.value.spot_x	= pPos->x ;
			ca.value.spot_y	= pPos->y ;
			XtVaSetValues (pThis->m_wgTopFrame, XtNconversionAttribute, &ca, NULL) ;
		}
		pThis->m_ConvAttr.value.spot_x	= pPos->x ;
		pThis->m_ConvAttr.value.spot_y	= pPos->y ;
		pThis->m_ConvAttr.mask	|= CASpotLocation ;
	}
	return	True ;
}

Boolean
XIMInputContext_SetPreeditColormap (
	register XIMInputContext*	pThis,
	register Colormap			colormap)
{
	if (! (pThis->m_ConvAttr.mask & CAColormap) ||
		pThis->m_ConvAttr.value.colormap != colormap) {
		pThis->m_ConvAttr.mask	|= CAColormap ;
		pThis->m_ConvAttr.value.colormap	= colormap ;

		if (pThis->m_wgTopFrame) {
			struct ConvAttrsMesg	ca ;

			ca.mask				= CAColormap ;
			ca.value.colormap	= colormap ;
			XtVaSetValues (pThis->m_wgTopFrame, XtNconversionAttribute, &ca, NULL) ;
		}
	}
	return	True ;
}

Boolean
XIMInputContext_SetPreeditStdColormap (
	register XIMInputContext*	pThis,
	register Atom				atStdColormap)
{
	register Widget		gw			= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	register Display*	pDisplay	= XtDisplay (gw) ;
	register Window		wndFocus ;
	XStandardColormap*	pStdColormap ;
	int					nCount ;

#if defined (DEBUG) || 0
	fprintf (stderr, "XIMInputContext_SetPreeditStdColormap (%p, %lx)\n",
					 pThis, atStdColormap) ;
#endif

	if (atStdColormap == None) 
		return	False ;

	wndFocus	= pThis->m_wndClient ;
	if (pThis->m_ConvAttr.mask & CAFocusWindow)
		wndFocus	= pThis->m_ConvAttr.value.focus_window ;
	if (wndFocus == None)
		return	False ;

	if (!XGetRGBColormaps (pDisplay, wndFocus, &pStdColormap, &nCount, atStdColormap))
		return	False ;

	pThis->m_atPStdColormap	= atStdColormap ;

	/*	標準でない colormap が割り当てられていれば、それで十分。*/
	if (! (pThis->m_ConvAttr.mask & CAColormap) && nCount > 0) {
		register Colormap	colormap	= pStdColormap->colormap ;
		pThis->m_ConvAttr.value.colormap	= colormap ;
		pThis->m_ConvAttr.mask				|= CAColormap ;

		if (pThis->m_wgTopFrame) {
			struct ConvAttrsMesg	ca ;

			ca.mask				= CAColormap ;
			ca.value.colormap	= colormap ;
			XtVaSetValues (pThis->m_wgTopFrame, XtNconversionAttribute, &ca, NULL) ;
		}
	}
	return	True ; 
}

Boolean
XIMInputContext_SetPreeditForeground (
	register XIMInputContext*	pThis,
	register unsigned long		ulForeground)
{
#if defined (DEBUG) || 0
	fprintf (stderr, "XIMInputContext_SetPreeditForeground (%p, %lx)\n",
			 pThis, ulForeground) ;
#endif
	if (! (pThis->m_ConvAttr.mask & CAForegroundPixel) ||
		pThis->m_ConvAttr.value.foreground != ulForeground) {
		pThis->m_ConvAttr.mask	|= CAForegroundPixel ;
		pThis->m_ConvAttr.value.foreground	= ulForeground ;
		if (pThis->m_wgTopFrame != NULL) {
			struct ConvAttrsMesg	ca ;

			ca.mask				= CAForegroundPixel ;
			ca.value.foreground	= ulForeground ;
			XtVaSetValues (pThis->m_wgTopFrame, XtNconversionAttribute, &ca, NULL) ;
		}
	}
	return	True ;
}

Boolean
XIMInputContext_SetPreeditBackground (
	register XIMInputContext*	pThis,
	register unsigned long		ulBackground)
{
#if defined (DEBUG) || 0
	fprintf (stderr, "XIMInputContext_SetPreeditBackground (%p, %lx)\n",
			 pThis, ulBackground) ;
#endif
	if (! (pThis->m_ConvAttr.mask & CABackgroundPixel) ||
		pThis->m_ConvAttr.value.background != ulBackground) {
		pThis->m_ConvAttr.mask	|= CABackgroundPixel ;
		pThis->m_ConvAttr.value.background	= ulBackground ;

		if (pThis->m_wgTopFrame != NULL) {
			struct ConvAttrsMesg	ca ;

			ca.mask				= CABackgroundPixel ;
			ca.value.background	= ulBackground ;
			XtVaSetValues (pThis->m_wgTopFrame, XtNconversionAttribute, &ca, NULL) ;
		}
	}
	return	True ;
}

Boolean
XIMInputContext_SetPreeditBackgroundPixmap (
	register XIMInputContext*	pThis,
	register Pixmap				pixmap)
{
	return	True ;
}

Boolean
XIMInputContext_SetPreeditFontSet (
	register XIMInputContext*	pThis,
	register const char*		pBaseName,
	register int				nBaseNameLength)
{
	register const char*	pPFontSetName ;
	register int			nPFontSetName ;

	pPFontSetName	= TVarbuffer_GetBuffer (&pThis->m_vbufPFontSetName) ;
	nPFontSetName	= TVarbuffer_GetUsage  (&pThis->m_vbufPFontSetName) - 1 ;

	if (! (pThis->m_ConvAttr.mask & CAFonts) ||
		nPFontSetName != nBaseNameLength ||
		strncmp (pPFontSetName, pBaseName, nPFontSetName) != 0) {
		register Display*		pDisplay ;
		register Widget			wgClient ;
		register const char*	pFontSetName ;
		int						nHeight, nAscent ;

		/*	フォントの変更の必要がある。*/
		TVarbuffer_Clear (&pThis->m_vbufPFontSetName) ;
		TVarbuffer_Add (&pThis->m_vbufPFontSetName, pBaseName, nBaseNameLength) ;
		TVarbuffer_Add (&pThis->m_vbufPFontSetName, "\0", 1) ;

		pFontSetName	= TVarbuffer_GetBuffer (&pThis->m_vbufPFontSetName) ;
		assert (pThis->m_pInputMethod != NULL) ;
		wgClient		= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
		assert (wgClient != NULL) ;
		pDisplay		= XtDisplay (wgClient) ;

#if defined (DEBUG) || 0
		fprintf (stderr, "PreeditFontSet => \"%s\"\n", pFontSetName) ;
#endif
		fontMgr_PrepareFontByName (pDisplay, pThis->m_fontset, (unsigned char*)pFontSetName) ;
		fontMgr_GetFontSetInfo (pThis->m_fontset, &nHeight, &nAscent) ;
		pThis->m_nFontHeight	= nHeight ;

		if (pThis->m_wgTopFrame != NULL) {
			struct ConvAttrsMesg	ca ;

			ca.mask				= CAFonts ;
			ca.value.fontset	= pThis->m_fontset ;
			XtVaSetValues (pThis->m_wgTopFrame, XtNconversionAttribute, &ca, NULL) ;
		}
		pThis->m_ConvAttr.mask	|= CAFonts ;
		pThis->m_ConvAttr.value.fontset	= pThis->m_fontset ;

		/*	フォントが変更されると line-spacing の情報は無効になる。*/
		pThis->m_ConvAttr.mask	&= ~CALineSpacing ;
	}
	return	True ;
}

Boolean
XIMInputContext_SetPreeditLineSpacing (
	register XIMInputContext*	pThis,
	register int 				nLineSpacing)
{
#if defined (DEBUG) || 0
	fprintf (stderr, "XIMInputContext_SetPreeditLineSpacing (%p, %d)\n",
			 pThis, nLineSpacing) ;
#endif
	if (! (pThis->m_ConvAttr.mask & CALineSpacing)) {
		pThis->m_ConvAttr.mask	|= CALineSpacing ;
		pThis->m_ConvAttr.value.linespacing	= nLineSpacing ;

		if (pThis->m_wgTopFrame != NULL) {
			struct ConvAttrsMesg	ca ;

			ca.mask					= CALineSpacing ;
			ca.value.linespacing	= nLineSpacing ;
			XtVaSetValues (pThis->m_wgTopFrame, XtNconversionAttribute, &ca, NULL) ;
		}
	}
	return	True ;
}

/*
 *(関数名)
 *	virtual Boolean
XIMInputContext_SetPreeditCursor (Cursor cursor) ;
 *(コメント)
 *	Preedit Area のカーソルを設定する。
 */
Boolean
XIMInputContext_SetPreeditCursor (
	register XIMInputContext*	pThis,
	register Cursor				cursor)
{
	return	False ;
}

/*
 *(関数名)
 *	virtual bool	GetPreeditArea (XRectangle* pArea) const ;
 *(コメント)
 *	Preedt Area の大きさを返す。
 *	…Client Window がリサイズを発行してくれないと Preedit Area
 *	の現在の大きさを正しく持つことはできない。
 *	この点…どう解決すべきか。(そもそもリサイズしたからって単純
 *	に領域を広げたくない場合もあるだろうし)
 */
Boolean
XIMInputContext_GetPreeditArea (
	register XIMInputContext*	pThis,
	register XRectangle*		pRect)
{
	assert (pThis != NULL) ;
	assert (pRect != NULL) ;

	/*
	 *	PreeditArea を持たないのであれば、必要な領域を返す必要はない。
	 */
	if ((pThis->m_dwInputStyle & XIMPreeditMask) == XIMPreeditNothing)
		return	True ;

	if (pThis->m_ConvAttr.mask & CAClientArea) {
		/*	既に表示領域が設定されている。*/
		memcpy (pRect, &pThis->m_ConvAttr.value.client_area, sizeof (XRectangle)) ;
	} else {
		if ((pThis->m_dwInputStyle & XIMPreeditMask) == XIMPreeditPosition){
			register Display*	pDisplay ;
			register Window		wndFocus ;

			/*
			 *	表示領域が設定されたことがない、
			 *		かつ
			 *	表示に必要な領域の設定もされたことがない
			 *
			 *	また、PreeditPosition のために AreaNeeded が設定されていると
			 *	いうわけではない。(PreeditArea なら AreaNeeded が設定されてい
			 *	る必要がある)
			 *
			 *	こういう場合には、Focus している Window の領域をとることにする。
			 */
			wndFocus	= (pThis->m_wndFocus == None)? pThis->m_wndClient : pThis->m_wndFocus ;
			if (wndFocus != None){
				register Widget	wgClient ;
				Window			wndRoot ;
				int				iX, iY ;
				unsigned int	iWidth, iHeight, iBorder, iDepth ;

				wgClient	= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
				pDisplay	= XtDisplay (wgClient) ;
				XGetGeometry (pDisplay, wndFocus, &wndRoot, &iX, &iY, &iWidth, &iHeight, &iBorder, &iDepth) ;
				pRect->x		= 0 ;
				pRect->y		= 0 ;
				pRect->width	= iWidth ;
				pRect->height	= iHeight ;
			} else {
				/*	Focus, Client Window もなく、ただ Area 情報を尋ねられてしまった…。*/
				return	False ;
			}
		} else {
			/*
			 *	恐らくは PreeditArea (つまり Preedit 領域の Area 情報が必要で
			 *	ある)なので、AreaNeeded が設定されている。
			 *	この場合には AreaNeeded 分だけ確保されたものという仮定のもとに
			 *	値を返す。
			 */
			if (pThis->m_ConvAttr.mask & CAClientAreaNeeded) {
				memcpy (pRect, &pThis->m_rcClientAreaNeeded, sizeof (XRectangle)) ;
			} else {
				XIMInputContext_GetPreeditAreaNeeded (pThis, pRect) ;
			}
		}
	}
	return	True ;
}

/*
 *(関数名)
 *	virtual bool	GetPreeditAreaNeeded (XRectangle* pArea) const ;
 *(コメント)
 *	必要とする Preedit Area の大きさをここで返さなければならない。
 *	どの程度の数値が妥当なのかは不明…。
 *	まず、最大値を入れてしまうべきなのか…それともこれだけは必要と
 *	いう最小値を入れてしまうべきなのか…。
 */
Boolean
XIMInputContext_GetPreeditAreaNeeded (
	register XIMInputContext*	pThis,
	register XRectangle*		pRect)
{
	assert (pThis != NULL) ;
	assert (pRect != NULL) ;

	/*
	 *	RootWindowStyle ならば PreeditArea は存在しないので、AreaNeeded
	 *	を返すことはできない。
	 */
	if ((pThis->m_dwInputStyle & XIMPreeditMask) == XIMPreeditNothing)
		return	True ;

	/*
	 *	必要とする領域をどうにか指定する。
	 */
	if (pThis->m_ConvAttr.mask & CAClientAreaNeeded) {
		/*
		 *	既に必要な領域が計算されている
		 *		あるいは
		 *	既に必要な領域がクライアントから設定されている
		 *	場合には、その数字を使う。
		 */
		memcpy (pRect, &pThis->m_rcClientAreaNeeded, sizeof (XRectangle)) ;
	} else {
		/*
		 *	必要な領域サイズは計算されておらず、その数値はサーバ任せとなっている。
		 */
		if ((pThis->m_dwInputStyle & XIMPreeditMask) == XIMPreeditArea){
			register int	nLineSpacing ;
			/*
			 *	PreeditArea の大きさをこちらで指定する必要がある…
			 *		もしくは
			 *	必要な大きさを申請するチャンスがある…
			 *	さて、どの程度要求するべきなのか？
			 */
			nLineSpacing	= XIMInputContext_GetPreeditLineSpacing (pThis) ;
			if ((pThis->m_dwInputStyle & XIMStatusMask) == XIMStatusArea &&
				(pThis->m_ConvAttr.mask & CAStatusAreaNeeded)) {
				pRect->x		= 0 ;
				pRect->y		= 0 ;
				pRect->width	= pThis->m_rcStatusAreaNeeded.width ;
				pRect->height	= nLineSpacing ;
			} else {
				pRect->x		= 0 ;
				pRect->y		= 0 ;
				pRect->width	= nLineSpacing * 20 ;
				pRect->height	= nLineSpacing * 20 ;
			}
		} else {
			/*
			 *	OverTheSpot Style の場合には設定しない…？
			 *	どうやら、ここに要求が来ることはなさそう。
			 */
			register Window		wndFocus ;
			wndFocus	= (pThis->m_wndFocus == None)? pThis->m_wndClient : pThis->m_wndFocus ;
			if (wndFocus != None){
				register Display*	pDisplay ;
				register Widget		wgClient ;
				Window			wndRoot ;
				int				iX, iY ;
				unsigned int	iWidth, iHeight, iBorder, iDepth ;

				wgClient	= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
				pDisplay	= XtDisplay (wgClient) ;
				XGetGeometry (pDisplay, wndFocus, &wndRoot, &iX, &iY, &iWidth, &iHeight, &iBorder, &iDepth) ;
				pRect->x		= 0 ;
				pRect->y		= 0 ;
				pRect->width	= iWidth ;
				pRect->height	= iHeight ;
			} else {
				//	Focus, Client Window もなく、ただ Area 情報を尋ねられてしまった…。
				return	False ;
			}
		}
	}
	return	True ;
}

/*
 *(関数名)
 *	virtual const XPoint	GetSpotLocation () const ;
 *(コメント)
 *	現在の Composition Window の位置を返す。
 *	この Attribute は Status にはない。
 */
Boolean
XIMInputContext_GetSpotLocation (
	register XIMInputContext*	pThis,
	register XPoint*			pPos)
{
	assert (pThis != NULL) ;
	assert (pPos  != NULL) ;
	/*
	 *	UIWindow から Text の Position を得る。
	 *	ただし、RootWindowStyle の場合には SpotLocation は意味を持たない。
	 *	XIMStyle & XIMPreeditPosition だった時には効果があるというところか？
	 */
	if ((pThis->m_dwInputStyle & XIMPreeditMask) == XIMPreeditPosition &&
		(pThis->m_ConvAttr.mask & CASpotLocation)) {
		pPos->x	= pThis->m_ConvAttr.value.spot_x ;
		pPos->y	= pThis->m_ConvAttr.value.spot_y ;
	} else {
		pPos->x	= 0 ;
		pPos->y	= 0 ;
	}
	return	True ;
} 

/*
 *(関数名)
 *	virtual const Colormap&	GetPreeditColormap () const ;
 *(コメント)
 *	PreeditArea の現在の Colormap を得る。
 *	デフォルトは当然のことながら、
 *		DefaultColormap (display, 0)
 *	を使っている。
 */
Colormap
XIMInputContext_GetPreeditColormap (
	register XIMInputContext*	pThis)
{
	if (! (pThis->m_ConvAttr.mask & CAColormap)) 
		return	None ;
	return	pThis->m_ConvAttr.value.colormap ;
}

/*
 *(関数名)
 *	virtual const Colormap&	GetPreeditColormap () const ;
 *(コメント)
 *	PreeditArea の Standard Colormap を得る。
 *	デフォルトは当然のことながら、
 *		DefaultColormap (display, 0)
 *	を使っている。
 */
Atom
XIMInputContext_GetPreeditStdColormap (
	register XIMInputContext*	pThis)
{
	return	pThis->m_atPStdColormap ;
}

unsigned long
XIMInputContext_GetPreeditForeground (
	register XIMInputContext*	pThis)
{
	if (! (pThis->m_ConvAttr.mask & CAForegroundPixel)) {
		/* What to do? */
	}
	return	pThis->m_ConvAttr.value.foreground ;
}

unsigned long
XIMInputContext_GetPreeditBackground (
	register XIMInputContext*	pThis)
{
	if (! (pThis->m_ConvAttr.mask & CABackgroundPixel)) {
		/* What to do? */
	}
	return	pThis->m_ConvAttr.value.background ;
}

Pixmap
XIMInputContext_GetPreeditBackgroundPixmap (
	register XIMInputContext*	pThis)
{
	if (! (pThis->m_ConvAttr.mask & CABackgroundPixmap)) {
		/* What to do? */
	}
	return	pThis->m_ConvAttr.value.background_pixmap ;
}

const char*
XIMInputContext_GetPreeditFontSet (
	register XIMInputContext*	pThis)
{
	return	TVarbuffer_GetBuffer (&pThis->m_vbufPFontSetName) ;
}

int	
XIMInputContext_GetPreeditLineSpacing (
	register XIMInputContext*	pThis)
{
	assert (pThis != NULL) ;

	if (! (pThis->m_ConvAttr.mask & (CALineSpacing | CAFonts)))
		return	DEFAULT_XIM_PREEDIT_LINESPACING ;

	if (pThis->m_ConvAttr.mask & CALineSpacing)
		return	pThis->m_ConvAttr.value.linespacing ;

	return	pThis->m_nFontHeight ;
}

Cursor
XIMInputContext_GetPreeditCursor (
	register XIMInputContext*	pThis)
{
	if (! (pThis->m_ConvAttr.mask & CACursor)) 
		return	None ;
	return	pThis->m_ConvAttr.value.cursor ;
}

/*
 *	Status 側の Interface
 */
Boolean
XIMInputContext_SetStatusArea (
	register XIMInputContext*	pThis,
	register const XRectangle*	pRect)
{
#if defined (DEBUG)
	fprintf (stderr, "XIMInputContext[%d]: SetStatusArea (%d, %d, %d, %d)\n",
			 pThis->m_woID,
			 pRect->x, pRect->y, pRect->width, pRect->height) ;
#endif

	if (! (pThis->m_ConvAttr.mask & CAStatusArea) ||
		! (pThis->m_ConvAttr.value.status_area.x == pRect->x &&
		   pThis->m_ConvAttr.value.status_area.y == pRect->y &&
		   pThis->m_ConvAttr.value.status_area.width  == pRect->width &&
		   pThis->m_ConvAttr.value.status_area.height == pRect->height)) {
		pThis->m_ConvAttr.mask	|= CAStatusArea ;
		pThis->m_ConvAttr.value.status_area	= *pRect ;

		if (pThis->m_wgTopFrame != NULL) {
			struct ConvAttrsMesg	ca ;

			ca.mask					= CAStatusArea ;
			ca.value.status_area	= *pRect ;
			XtVaSetValues (pThis->m_wgTopFrame, XtNconversionAttribute, &ca, NULL) ;
		}
	}
	return	True ;
}

Boolean
XIMInputContext_SetStatusAreaNeeded (
	register XIMInputContext*	pThis,
	register const XRectangle*	pRect)
{
	/*	ClientAreaNeeded が入ると、ClientArea のサイズは
	 *	こちらにひっぱられる。
	 */
#if defined (DEBUG)
	fprintf (stderr, "XIMInputContext[%d]: SetStatusAreaNeeded (%d, %d, %d, %d)\n",
			 pThis->m_woID,
			 pRect->x, pRect->y, pRect->width, pRect->height) ;
#endif
	if (! (pThis->m_ConvAttr.mask & CAStatusAreaNeeded) ||
		! (pThis->m_rcStatusAreaNeeded.x == pRect->x &&
		   pThis->m_rcStatusAreaNeeded.y == pRect->y &&
		   pThis->m_rcStatusAreaNeeded.width  == pRect->width &&
		   pThis->m_rcStatusAreaNeeded.height == pRect->height)) {
		pThis->m_ConvAttr.mask	|= CAStatusAreaNeeded ;
		pThis->m_rcStatusAreaNeeded	= *pRect ;
	}
	return	True ;
}

Boolean
XIMInputContext_SetStatusColormap (
	register XIMInputContext*	pThis,
	register Colormap			colormap)
{
	/*	currently not implemented. */
	return	True ;
}

Boolean
XIMInputContext_SetStatusStdColormap (
	register XIMInputContext*	pThis,
	register Atom				atStdColormap)
{
	/*	currently not implemented. */
	return	True ; 
}

Boolean
XIMInputContext_SetStatusForeground (
	register XIMInputContext*	pThis,
	register unsigned long		ulForeground)
{
	/*	currently not implemented. */
	return	True ;
}

Boolean
XIMInputContext_SetStatusBackground (
	register XIMInputContext*	pThis,
	register unsigned long		ulBackground)
{
	/*	currently not implemented. */
	return	True ;
}

Boolean
XIMInputContext_SetStatusBackgroundPixmap (
	register XIMInputContext*	pThis,
	register Pixmap				pixmap)
{
	/*	currently not implemented. */
	return	True ;
}

/*	Status 領域は今は何もしていないので設定は不可能。
 */
Boolean
XIMInputContext_SetStatusFontSet (
	register XIMInputContext*	pThis,
	register const char*		pBaseName,
	register int				nBaseNameLength)
{
	/*	currently not implemented. */
	return	True ;
}

Boolean
XIMInputContext_SetStatusLineSpacing (
	register XIMInputContext*	pThis,
	register int				nLineSpacing)
{
	/*	currently not implemented. */
	return	True ;
}

Boolean
XIMInputContext_SetStatusCursor (
	register XIMInputContext*	pThis,
	register Cursor				cursor)
{
	/*	currently not implemented. */
	return	True ;
}

/*
 *(関数名)
 *	virtual bool	GetStatusArea (XRectangle* pArea) const ;
 *(コメント)
 *	Preedt Area の大きさを返す。
 *	…Client Window がリサイズを発行してくれないと Status Area
 *	の現在の大きさを正しく持つことはできない。
 *	この点…どう解決すべきか。(そもそもリサイズしたからって単純
 *	に領域を広げたくない場合もあるだろうし)
 */
Boolean
XIMInputContext_GetStatusArea (
	register XIMInputContext*	pThis,
	register XRectangle*		pRect)
{
	assert (pThis != NULL) ;
	assert (pRect != NULL) ;
	if ((pThis->m_dwInputStyle & XIMStatusMask) == XIMStatusNothing)
		return	False ;

	if (pThis->m_ConvAttr.mask & CAStatusArea) {
		memcpy (pRect, &pThis->m_ConvAttr.value.status_area, sizeof (XRectangle)) ;
	} else {
		if ((pThis->m_dwInputStyle & XIMStatusMask) == XIMStatusArea &&
			(pThis->m_ConvAttr.mask & CAStatusAreaNeeded)) {
			memcpy (pRect, &pThis->m_rcStatusAreaNeeded, sizeof (XRectangle)) ;
		} else {
			register int	nLineSpacing ;

			pRect->x	= 0 ;
			pRect->y	= 0 ;
			nLineSpacing	= XIMInputContext_GetStatusLineSpacing (pThis) ;
			if ((pThis->m_dwInputStyle & XIMPreeditMask) == XIMPreeditPosition){
				/*	そもそも line spacing って設定されてないから、ここは修正する
				 *	必要がある。*/
				pRect->width	= nLineSpacing * 80 / 2 ;
			} else {
				pRect->width	= nLineSpacing * 7 / 2 ;
			}
			pRect->height	= nLineSpacing ;
		}
	}
	return	True ;
}

/*
 *(関数名)
 *	virtual bool	GetStatusAreaNeeded (XRectangle* pArea) const ;
 *(コメント)
 *	必要とする Status Area の大きさをここで返さなければならない。
 *	どの程度の数値が妥当なのかは不明…。
 *	まず、最大値を入れてしまうべきなのか…それともこれだけは必要と
 *	いう最小値を入れてしまうべきなのか…。
 */
Boolean
XIMInputContext_GetStatusAreaNeeded (
	register XIMInputContext*	pThis,
	register XRectangle*		pRect)
{
	assert (pThis != NULL) ;
	if ((pThis->m_dwInputStyle & XIMStatusMask) == XIMStatusNothing)
		return	False ;
	if (pThis->m_ConvAttr.mask & CAStatusAreaNeeded) {
		memcpy (pRect, &pThis->m_rcStatusAreaNeeded, sizeof (XRectangle)) ;
	} else {
		register int	nLineSpacing ;
		pRect->x		= 0 ;
		pRect->y		= 0 ;

		nLineSpacing	= XIMInputContext_GetStatusLineSpacing (pThis) ;
		if ((pThis->m_dwInputStyle & XIMPreeditMask) == XIMPreeditPosition){
			pRect->width	= nLineSpacing * 80 / 2 ;
		} else {
			pRect->width	= nLineSpacing * 7 / 2 ;
		}
		pRect->height	= nLineSpacing ;
	}
	return	True ;
}

/*
 *(関数名)
 *	virtual const Colormap&	GetStatusColormap () const ;
 *(コメント)
 *	StatusArea の現在の Colormap を得る。
 *	デフォルトは当然のことながら、
 *		DefaultColormap (display, 0)
 *	を使っている。
 */
Colormap
XIMInputContext_GetStatusColormap (
	register XIMInputContext*	pThis)
{
	return	None ;
}

/*
 *(関数名)
 *	virtual const Colormap&	GetStatusColormap () const ;
 *(コメント)
 *	StatusArea の Standard Colormap を得る。
 *	デフォルトは当然のことながら、
 *		DefaultColormap (display, 0)
 *	を使っている。
 */
Atom
XIMInputContext_GetStatusStdColormap (
	register XIMInputContext*	pThis)
{
	return	None ;
}

unsigned long
XIMInputContext_GetStatusForeground (
	register XIMInputContext*	pThis)
{
	/*	not implemented, both status and peedit must have the same value? */
	return	XIMInputContext_GetPreeditForeground (pThis) ;
}

unsigned long
XIMInputContext_GetStatusBackground (
	register XIMInputContext*	pThis)
{
	/*	not implemented, both status and peedit must have the same value? */
	return	XIMInputContext_GetPreeditBackground (pThis) ;
}

Pixmap
XIMInputContext_GetStatusBackgroundPixmap (
	register XIMInputContext*	pThis)
{
	return	XIMInputContext_GetPreeditBackgroundPixmap (pThis) ;
}

const char*
XIMInputContext_GetStatusFontSet (
	register XIMInputContext*	pThis)
{
	return	NULL ;	/* I have no status fontset. */ 
}

/*
 *
 */
int
XIMInputContext_GetStatusLineSpacing (
	register XIMInputContext*	pThis)
{
	/* Hmmm... I don't know what to do. So, I return the same value
	 * with preedit line spacing. */
	return	XIMInputContext_GetPreeditLineSpacing (pThis) ;
}

Cursor
XIMInputContext_GetStatusCursor (
	register XIMInputContext*	pThis)
{
	return	XIMInputContext_GetPreeditCursor (pThis) ;
}

Boolean
XIMInputContext_SetAttributes (
	register XIMInputContext*	pThis)
{
	struct ConvAttrsMesg	ca ;

	/*	Preedit/Status の両方を同時に設定する。skkinput3 では片方ずつ
	 *	だったけれども。
	 */
	memcpy (&ca, &pThis->m_ConvAttr, sizeof (struct ConvAttrsMesg)) ;
	ca.mask	&= ~(CAInputStyle | CAClientAreaNeeded | CAStatusAreaNeeded) ;
	XtVaSetValues (pThis->m_wgTopFrame, XtNconversionAttribute, &ca, NULL) ;
	return	True ;
}

Boolean
XIMInputContext_Activate (
	register XIMInputContext*		pThis,
	register Boolean				fActive)
{
	assert (pThis != NULL) ;
	assert (pThis->m_wgTopFrame != NULL) ;

	/*	むう。どうするか？
	 */
	return	True ;
}

Boolean
ximInputContext_createFrame (
	register XIMInputContext*	pThis)
{
	register Widget	wgFrame, wgClient ;
	register Window	wndFocus ;
	Arg				rArg [12] ;
	register int	nArg ;
	register const char*		strClassName ;
	register WidgetClass		pClass ;
	register HistoryListNode*	histNode ;

	wgClient	= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	nArg		= 0 ;
	XtSetArg (rArg [nArg], XtNmappedWhenManaged,	False) ; nArg ++ ;
	XtSetArg (rArg [nArg], XtNclientWindow,			pThis->m_wndClient) ; nArg ++ ;
	if (! (pThis->m_ConvAttr.mask & CAFocusWindow)) {
		wndFocus	= pThis->m_wndClient ;
	} else {
		wndFocus	= pThis->m_ConvAttr.value.focus_window ;
	}
	XtSetArg (rArg [nArg], XtNinput,		False) ;	nArg ++ ;

	switch (pThis->m_dwInputStyle & XIMPreeditMask) {
	case	XIMPreeditPosition:
		strClassName	= "overthespot" ;
		pClass			= overthespotWinWidgetClass ;
		break ;
	case	XIMPreeditArea:
		strClassName	= "offthespot" ;
		pClass			= offthespotWinWidgetClass ;
		break ;
		/*	sorry, this code is not implemented yet. */
	case	XIMPreeditCallbacks:
		strClassName	= "onthespot" ;
		pClass			= onthespotWinWidgetClass ;
		break ;
	case	XIMPreeditNothing:
	case	XIMPreeditNone:
	default:
		strClassName	= "separate" ;
		pClass			= separateWinWidgetClass ;
		break ;
	}
	histNode	= history_setup (0, pThis->m_wndClient) ;

	wgFrame		= XtVaCreateWidget
		(strClassName, pClass, wgClient, 
		 XtNmappedWhenManaged,	False, 
		 XtNclientWindow,		pThis->m_wndClient,
		 XtNconversionHistory,	histNode, 
		 XtNprobeWindow,		None,
		 XtNinput,				False,
		 NULL) ;
	if (wgFrame == NULL) {
		if (histNode != NULL)
			free (histNode) ;
		return	False ;
	}
	pThis->m_wgTopFrame	= wgFrame ;

	add_myeventhandler (XtDisplay (wgClient), pThis->m_wndClient, XtWindow (wgFrame), NO_EVENT_HANDLE, StructureNotifyMask ) ;
	XtCallCallbacks (XtParent (wgClient), XtNsetupInputWindowNotify, wgFrame) ;

	XtAddCallback (wgFrame, XtNtextNotify,	 ximInputContext_onTextNotify,    (XtPointer)pThis) ;
	XtAddCallback (wgFrame, XtNendNotify,	 ximInputContext_onEndNotify,     (XtPointer)pThis) ;
	XtAddCallback (wgFrame, XtNkeybackNotify,ximInputContext_onKeyBackNotify, (XtPointer)pThis) ;

	if (pClass == onthespotWinWidgetClass) {
		XtAddCallback (wgFrame, XtNpreeditStartCallback, ximInputContext_onPreeditStart, (XtPointer)pThis) ;
		XtAddCallback (wgFrame, XtNpreeditDrawCallback, ximInputContext_onPreeditDraw, (XtPointer)pThis) ;
		XtAddCallback (wgFrame, XtNpreeditCaretCallback, ximInputContext_onPreeditCaret, (XtPointer)pThis) ;
		XtAddCallback (wgFrame, XtNpreeditDoneCallback, ximInputContext_onPreeditDone, (XtPointer)pThis) ;
		XtAddCallback (wgFrame, XtNstatusStartCallback, ximInputContext_onStatusStart, (XtPointer)pThis) ;
		XtAddCallback (wgFrame, XtNstatusDrawCallback, ximInputContext_onStatusDraw, (XtPointer)pThis) ;
		XtAddCallback (wgFrame, XtNstatusDoneCallback, ximInputContext_onStatusDone, (XtPointer)pThis) ;
	}

	XIMInputContext_SetAttributes (pThis) ;
	XtRealizeWidget (wgFrame) ;
	XFlush (XtDisplay (wgFrame)) ;
	return	True ;
}

/*	XIM_COMMIT のパケット同士は連結するのだが、改行だけのパケットは
 *	つないではいけない。つなぐと「改行」が入らなくなる実装があるので。
 *	Spool する前の段階で「改行」のみのパケットをわざわざ生成している。
 */
Boolean
ximInputContext_packetToCombinep (
	register XIMPacket*			pPacket)
{
	XIMData					imData ;
	int						nMajor ;
	register unsigned int	uBitMask ;

	assert (pPacket != NULL) ;

	XIMPacket_GetHeader (pPacket, &nMajor, NULL) ;
	if (nMajor != XIM_COMMIT) 
		return	False ;
	XIMData_Initialize (&imData, XIMPacket_GetData (pPacket), XIMPacket_GetEndian (pPacket)) ;
	XIMData_Forward8  (&imData, XIM_HEADER_SIZE + 2 + 2) ;
	uBitMask	= XIMData_GetCard16 (&imData) ;
	return	(uBitMask & 4)? False : True ;
}

XIMPacket*
ximInputContext_combineXimCommit (
	register XIMInputContext*	pThis,
	register XIMPacket*			pSrcPacket1,
	register XIMPacket*			pSrcPacket2)
{
	register XIMPacket*	pPacket ;
	XIMData			imSrc ;
	register int	nctext, nctotal, nIndex ;
	CARD16			uMask ;

	assert (pThis != NULL) ;
	assert (pSrcPacket1 != NULL) ;
	assert (pSrcPacket2 != NULL) ;

	pPacket	= XIMPacket_Create (XIMPacket_GetEndian (pSrcPacket1)) ;
	if (pPacket == NULL)
		return	NULL ;
#if defined (DEBUG)
	fprintf (stderr, "Combine X_COMMIT\n") ;
	fprintf (stderr, "Packet1:\n") ;
	XIMPacket_Show (pSrcPacket1) ;
	fprintf (stderr, "Packet2:\n") ;
	XIMPacket_Show (pSrcPacket2) ;
#endif
	XIMPacket_SetHeader (pPacket, XIM_COMMIT, 0) ;
	XIMPacket_AddCard16 (pPacket, XIMInputMethod_GetID  (pThis->m_pInputMethod)) ;
	XIMPacket_AddCard16 (pPacket, XIMInputContext_GetID (pThis)) ;
	XIMPacket_SetInputContext (pPacket, pThis) ;
	XIMPacket_SetSyncMode  (pPacket, XIMPacket_GetSyncMode (pSrcPacket1)) ;
	XIMPacket_GetCard16    (pSrcPacket1, XIM_HEADER_SIZE + 2 + 2, &uMask) ;
	XIMPacket_AddBitmask16 (pPacket, uMask) ;
	nIndex	= XIMPacket_GetDataSize (pPacket) ;
	XIMPacket_AddCard16 (pPacket, 0 /* dummy */) ;

	XIMData_Initialize (&imSrc, XIMPacket_GetData (pSrcPacket1), XIMPacket_GetEndian (pSrcPacket1)) ;
	XIMData_Forward8  (&imSrc, XIM_HEADER_SIZE) ;
	XIMData_Forward16 (&imSrc, 3 /* IMID + IMIC + Bitmask16 */) ;
	nctext	= XIMData_GetCard16 (&imSrc) ;
	nctotal	= nctext ;
	XIMPacket_AddString8 (pPacket, XIMData_GetHead (&imSrc), nctext) ;

	XIMData_Initialize (&imSrc, XIMPacket_GetData (pSrcPacket2), XIMPacket_GetEndian (pSrcPacket2)) ;
	XIMData_Forward8  (&imSrc, XIM_HEADER_SIZE) ;
	XIMData_Forward16 (&imSrc, 3 /* IMID + IMIC + Bitmask16 */) ;
	nctext	= XIMData_GetCard16 (&imSrc) ;
	nctotal	+= nctext ;
	XIMPacket_AddString8 (pPacket, XIMData_GetHead (&imSrc), nctext) ;
	XIMPacket_AddPad (pPacket, nctotal) ;
	XIMPacket_SetCard16 (pPacket, nIndex, nctotal) ;
	XIMPacket_SetLength (pPacket) ;
#if defined (DEBUG)
	fprintf (stderr, "Result Packet:\n") ;
	XIMPacket_Show (pPacket) ;
#endif
	return	pPacket ;
}

void
ximInputContext_onKeyBackNotify (
	register Widget		wgFrame,
	register XtPointer	closure,
	register XtPointer	call_data)
{
	register XIMInputContext*	pThis	= (XIMInputContext *) closure ;
	register XEvent*			pEvent	= (XEvent*) call_data ;
	register Widget				wgClient ;

	wgClient	= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	XIMClient_ForwardEvent (wgClient, pThis->m_pInputMethod, pThis, pEvent) ;
	return ;
}

void
ximInputContext_onEndNotify (
	register Widget		wgFrame,
	register XtPointer	closure,
	register XtPointer	call_data)
{
	register XIMInputContext*	pThis	= (XIMInputContext *) closure ;
	register Widget				wgClient ;

	wgClient	= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;

	if (call_data != NULL)
		history_close (XtDisplay (wgClient), call_data) ;

#if defined (DEBUG)
	fprintf (stderr, "ximInputMethod_onEndNotify (%p)\n", pThis) ;
#endif
	XIMClient_ControlEventFlow (wgClient, pThis->m_pInputMethod, pThis, False) ;
	XIMInputContext_EndConversion (pThis) ;
	pThis->m_wgTopFrame	= NULL ;
	return ;
}

void
ximInputContext_onTextNotify (
	register Widget		wgFrame,
	register XtPointer	closure,
	register XtPointer	call_data)
{
	register XIMInputContext*	pThis	= (XIMInputContext *) closure ;
	register struct myChar*		pText		= (struct myChar*)call_data ;
	register Widget				wgClient ;

	wgClient	= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	XIMClient_CommitString (wgClient, pThis->m_pInputMethod, pThis, pText) ;
	return ;
}

void
ximInputContext_onPreeditStart (
	register Widget		wgFrame,
	register XtPointer	closure,
	register XtPointer	call_data)
{
	register XIMInputContext*	pThis	= (XIMInputContext*) closure ;
	register Widget				wgClient ;
	register int				nInputMethodID ;

	assert (wgFrame != NULL) ;
	assert (pThis   != NULL) ;

#if defined (DEBUG) || 0
	fprintf (stderr, "ximInputContext_onPreeditStart (%p, %p, %p)\n",
			 wgFrame, closure, call_data) ;
#endif
	wgClient		= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	nInputMethodID	= XIMInputMethod_GetID (pThis->m_pInputMethod) ;
	XIMClient_WritePreeditStart (wgClient, nInputMethodID, pThis) ;
	return ;
}

void
ximInputContext_onPreeditDraw (
	register Widget		wgFrame,
	register XtPointer	closure,
	register XtPointer	call_data)
{
	register XIMInputContext*	pThis	= (XIMInputContext*) closure ;
	register Widget				wgClient ;
	register int				nInputMethodID ;
	register const TOnTheSpotDrawArg*	pArg ;

	assert (wgFrame != NULL) ;
	assert (pThis   != NULL) ;

#if defined (DEBUG) || 0
	fprintf (stderr, "ximInputContext_onPreeditDraw (%p, %p, %p)\n",
			 wgFrame, closure, call_data) ;
#endif

	wgClient		= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	pArg			= (const TOnTheSpotDrawArg *)call_data ;
	assert (wgClient != NULL) ;
	assert (pArg     != NULL) ;
	nInputMethodID	= XIMInputMethod_GetID (pThis->m_pInputMethod) ;
	XIMClient_WritePreeditDraw (wgClient, nInputMethodID, pThis, pArg) ;
	return ;
}

void
ximInputContext_onPreeditCaret (
	register Widget		wgFrame,
	register XtPointer	closure,
	register XtPointer	call_data)
{
	register XIMInputContext*	pThis	= (XIMInputContext*) closure ;
	register Widget				wgClient ;
	register int				nInputMethodID ;
	register const TOnTheSpotDrawArg*	pArg ;

	assert (wgFrame != NULL) ;
	assert (pThis   != NULL) ;

#if defined (DEBUG) || 0
	fprintf (stderr, "ximInputContext_onPreeditCaret (%p, %p, %p)\n",
			 wgFrame, closure, call_data) ;
#endif
	wgClient		= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	pArg			= (const TOnTheSpotDrawArg *)call_data ;
	assert (wgClient != NULL) ;
	assert (pArg     != NULL) ;
	nInputMethodID	= XIMInputMethod_GetID (pThis->m_pInputMethod) ;
	XIMClient_WritePreeditCaret (wgClient, nInputMethodID, pThis, pArg) ;
	return ;
}

void
ximInputContext_onPreeditDone (
	register Widget		wgFrame,
	register XtPointer	closure,
	register XtPointer	call_data)
{
	register XIMInputContext*	pThis	= (XIMInputContext*) closure ;
	register Widget				wgClient ;
	register int				nInputMethodID ;

	assert (wgFrame != NULL) ;
	assert (pThis   != NULL) ;

#if defined (DEBUG) || 0
	fprintf (stderr, "ximInputContext_onPreeditDone (%p, %p, %p)\n",
			 wgFrame, closure, call_data) ;
#endif
	wgClient		= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	nInputMethodID	= XIMInputMethod_GetID (pThis->m_pInputMethod) ;
	XIMClient_WritePreeditDone (wgClient, nInputMethodID, pThis) ;
	return ;
}

void
ximInputContext_onStatusStart (
	register Widget		wgFrame,
	register XtPointer	closure,
	register XtPointer	call_data)
{
	register XIMInputContext*	pThis	= (XIMInputContext*) closure ;
	register Widget				wgClient ;
	register int				nInputMethodID ;

	assert (wgFrame != NULL) ;
	assert (pThis   != NULL) ;

	wgClient		= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	nInputMethodID	= XIMInputMethod_GetID (pThis->m_pInputMethod) ;
	XIMClient_WriteStatusStart (wgClient, nInputMethodID, pThis) ;
	return ;
}

void
ximInputContext_onStatusDraw (
	register Widget		wgFrame,
	register XtPointer	closure,
	register XtPointer	call_data)
{
	register XIMInputContext*	pThis	= (XIMInputContext*) closure ;
	register Widget				wgClient ;
	register int				nInputMethodID ;
	register const TOnTheSpotDrawArg*	pArg ;

	assert (wgFrame != NULL) ;
	assert (pThis   != NULL) ;

	wgClient		= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	pArg			= (const TOnTheSpotDrawArg *)call_data ;
	assert (wgClient != NULL) ;
	assert (pArg     != NULL) ;
	nInputMethodID	= XIMInputMethod_GetID (pThis->m_pInputMethod) ;
	XIMClient_WriteStatusDraw (wgClient, nInputMethodID, pThis, pArg) ;
	return ;
}

void
ximInputContext_onStatusDone (
	register Widget		wgFrame,
	register XtPointer	closure,
	register XtPointer	call_data)
{
	register XIMInputContext*	pThis	= (XIMInputContext*) closure ;
	register Widget				wgClient ;
	register int				nInputMethodID ;

	assert (wgFrame != NULL) ;
	assert (pThis   != NULL) ;

	wgClient		= XIMInputMethod_GetClient (pThis->m_pInputMethod) ;
	nInputMethodID	= XIMInputMethod_GetID (pThis->m_pInputMethod) ;
	XIMClient_WriteStatusDone (wgClient, nInputMethodID, pThis) ;
	return ;
}

