/* # skkinput (Simple Kana-Kanji Input)
 * OffWin.c --- Making OffTheSpotWinWidget.
 * 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/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 "OffWinP.h"
#include "config.h"
#include "skkkey.h"
#include "skkel.h"
#include "Canvas.h"
#include "WmcloseShell.h"
#include "MyError.h"
#include "FontMgr.h"
#include "draw.h"
#include "MyDispatch.h"

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

#define offset(field) XtOffsetOf( OffthespotWinRec, offthespotWin.field)
#define goffset(field) XtOffsetOf( WidgetRec, core.field )

static XtResource OFFW_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},
  /* offthespot で利用する漢字フォント及びローマ字フォント。*/
  { 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 },
  { XtNtextNotify,	XtCCallback, XtRCallback, sizeof (XtCallbackList),
	offset (m_lstTextCallback),	XtRCallback, (caddr_t) NULL },
  /* egg 互換の j-newline を許すか否か。*/
  { XtNeggLikeNewline, XtCEggLikeNewline, XtRImmediate, sizeof( Boolean ),
    XtOffsetOf( OffthespotWinRec, offthespotWin.buffer.egg_like_newline ),
    XtRImmediate, (XtPointer) FALSE},
  /* chat-adapter-mode か否か。*/
  { XtNchatAdapter, XtCChatAdapter, XtRImmediate, sizeof( Boolean ),
    XtOffsetOf( OffthespotWinRec, offthespotWin.buffer.chat_adapter ),
    XtRImmediate, (XtPointer) FALSE},
  { XtNjisyoDirty, XtCJisyoDirty, XtRImmediate, sizeof( Boolean ),
    XtOffsetOf( OffthespotWinRec, offthespotWin.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 },
  /* カーソルを常に南側に表示する…。*/
  { XtNsouthCursor, XtCSouthCursor, XtRBoolean, sizeof( Boolean ),
    offset( south_cursor ), 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 },
  /* Subwindow がフォーカスを返すウィンドウを指定する。*/
  { XtNprobeWindow, XtCProbeWindow, XtRImmediate, sizeof( Window ),
    offset( probe_window ), XtRImmediate, ( XtPointer )None },
  /* 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( OffthespotWinRec, offthespotWin.buffer.toggleShiftMode ),
    XtRImmediate, ( XtPointer )FALSE },
  { XtNcontrolHaTugiDeYukou, XtCControlHaTugiDeYukou, XtRBoolean,
    sizeof( Boolean ), 
    XtOffsetOf( OffthespotWinRec, offthespotWin.buffer.toggleControlMode ),
    XtRImmediate, ( XtPointer )FALSE },
  {	XtNinput,	XtCInput,	XtRBoolean,	sizeof (Boolean),
	offset (m_fInputFocus), XtRImmediate, (XtPointer) TRUE, },
} ;

#undef offset
#undef goffset

/*
 * プロトタイプ宣言。
 */
/*
 * このウィジェットを構成している基本要素となる関数たち。
 */
static void OFFW_Initialize
( Widget greq, Widget gnew, ArgList args, Cardinal *num_args ) ;
static void OFFW_Realize
( Widget gw, XtValueMask *valueMask, XSetWindowAttributes *attrs ) ;
static void OFFW_Redisplay
( Widget gw, XEvent *event, Region region ) ;
static void OFFW_Destroy( Widget gw ) ;
static Boolean OFFW_SetValues
( Widget current, Widget request, Widget new,
  ArgList args, Cardinal *num_args ) ;
static void KeyDownEventHandler
( Widget w, XEvent *event, String *params, Cardinal *num_params ) ;
static void FocusEventHandler
( Widget gw, XEvent *xevent, String *params, Cardinal *num_params ) ;

static void OFFW_CreateAllGCs( Widget gw ) ;
static void OFFW_CreateMinibufferGCs( Widget gw ) ;
static void OFFW_ReleaseAllGCs( Widget gw ) ;
static void OFFW_ReleaseMinibufferGCs( Widget gw ) ;

static int OFFW_ChangeAttributes
( Widget gw, unsigned long valuemask, struct ConvAttrs *values ) ;
static void OFFW_resetupModeWindow( Widget gw ) ;
static void OFFW_ReconfigureColor
( Widget gw, unsigned long valuemask ) ;

static void OFFW_ConfigureMinibuffer( Widget gw ) ;

static void OFFW_RedrawScreen( Widget gw ) ;
static int OFFW_ReconfigureFocusPosition
( Widget gw ) ;

static int focusCheck( Widget gw ) ;
/*
 * callbacks
 */
static void Canvas_Redisplay
( Widget gw, Window win ) ;
static void Minibuffer_RedisplayCallback
( Widget gw, caddr_t client, caddr_t caller ) ;
static void Modeshell_Redisplay
( Widget gw, Window win ) ;
static void Modeshell_Display
( Widget gw, Window win ) ;
static void Canvas_DestroyCallback
( Widget gw, caddr_t client, caddr_t caller ) ;
static void OFFW_wmMessageCloseCallback
( Widget gw, caddr_t client, caddr_t caller ) ;
static void OFFW_wmShellDestroyCallback
( Widget gw, caddr_t client, caddr_t caller ) ;
static void		OffWin_fixcallback		(Widget, XtPointer, XtPointer) ;

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

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

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

OffthespotWinClassRec offthespotWinClassRec = {
    { /* core fields */
    /* superclass		*/	&widgetClassRec,
    /* class_name		*/	"Offthespot",
    /* size			*/	sizeof( OffthespotWinRec ),
    /* class_initialize		*/	NULL,
    /* class_part_initialize	*/	NULL,
    /* class_inited		*/	FALSE,
    /* initialize		*/	OFFW_Initialize,
    /* initialize_hook		*/	NULL,
    /* realize			*/	OFFW_Realize,
    /* actions			*/	offthespotWinActionsTable,
    /* num_actions		*/	XtNumber( offthespotWinActionsTable ),
    /* resources		*/	OFFW_resources,
    /* num_resources		*/	XtNumber( OFFW_resources ),
    /* xrm_class		*/	NULLQUARK,
    /* compress_motion		*/	TRUE,
    /* compress_exposure	*/	TRUE,
    /* compress_enterleave	*/	TRUE,
    /* visible_interest		*/	FALSE,
    /* destroy			*/	OFFW_Destroy,
    /* resize			*/	NULL,
    /* expose			*/	OFFW_Redisplay,
    /* set_values		*/	OFFW_SetValues,
    /* set_values_hook		*/	NULL,
    /* set_values_almost	*/	XtInheritSetValuesAlmost,
    /* get_values_hook		*/	NULL,
    /* accept_focus		*/	NULL,
    /* version			*/	XtVersion,
    /* callback_private		*/	NULL,
    /* tm_table			*/	defaultOffthespotWinTranslations,
    /* query_geometry		*/	XtInheritQueryGeometry,
    }
};

WidgetClass offthespotWinWidgetClass =
( WidgetClass )&offthespotWinClassRec ;

static void OFFW_InitializeHistory( Widget gw )
{
	OffthespotWinWidget w = ( OffthespotWinWidget )gw ;

	if( w->offthespotWin.historyAttribute == NULL ){
		return ;
	}
	/* 以前に設定したことがあれば…。*/
	if( w->offthespotWin.historyAttribute->overthespot_like_input < 0 ){
		/* X Resource の側から設定する。*/
		w->offthespotWin.buffer.overthespot_like_input = 
			w->offthespotWin.overthespotLikeInput ;
	} else {
		/* 前回の設定を流用する。*/
		w->offthespotWin.buffer.overthespot_like_input = 
			w->offthespotWin.historyAttribute->overthespot_like_input ;
	}
	/* ヒストリの初期化をする。*/
	w->offthespotWin.buffer.historybuffer =
		w->offthespotWin.historyAttribute->history ;
	w->offthespotWin.buffer.hist_start = 
		w->offthespotWin.historyAttribute->history_start ;
	w->offthespotWin.buffer.hist_end = 
		w->offthespotWin.historyAttribute->history_end ;
	w->offthespotWin.buffer.histcurbackbuffer =
		w->offthespotWin.historyAttribute->histcurbak ;
	w->offthespotWin.buffer.hist_cur = -1 ;
	
	/* 入力モードの初期化をする。*/
	w->offthespotWin.buffer.chat_adapter =
		w->offthespotWin.historyAttribute->chat_adapter ;
	w->offthespotWin.buffer.egg_like_newline =
		w->offthespotWin.historyAttribute->egg_nl ;
	
	/* 仮名モードの初期化をする。*/
	w->offthespotWin.buffer.topbuffer->j_mode =
		w->offthespotWin.historyAttribute->j_mode ;
	w->offthespotWin.buffer.topbuffer->j_zenkaku =
		w->offthespotWin.historyAttribute->j_zenkaku ;
	w->offthespotWin.buffer.topbuffer->j_katakana_mode =
		w->offthespotWin.historyAttribute->j_katakana_mode ;
	return ;
}

static void OFFW_Initialize 
( Widget greq, Widget gnew, ArgList args, Cardinal *num_args )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gnew ;
  int i ;

  /* アルファベット表示のための GC を作る。*/
  w->offthespotWin.background = w->core.background_pixel ;
  w->offthespotWin.foreground = w->offthespotWin.puppixel ;
  w->offthespotWin.colormap   = w->core.colormap ;
  w->offthespotWin.oforeground = w->offthespotWin.foreground ;
  w->offthespotWin.obackground = w->offthespotWin.background ;
  
  /* フォントセットを初期化する。*/
  for( i = 0 ; i < NUMBER_OF_CHARSET ; i ++ ){
    w->offthespotWin.fontset[ i ] = NULL ;
    w->offthespotWin.minibuf_fontset[ i ] = NULL ;
  }
  w->offthespotWin.gc = w->offthespotWin.rgc = NULL ;
  w->offthespotWin.minibuf_gc = w->offthespotWin.minibuf_rgc = NULL ;

  /* デフォルトのフォントに設定する。*/
  fontMgr_copyDefaultFontSet
    ( XtDisplay( gnew ), w->offthespotWin.fontset ) ;
  fontMgr_copyDefaultMinibufFontSet
    ( XtDisplay( gnew ), w->offthespotWin.minibuf_fontset ) ;
  /* デフォルトのフォントの情報を抜き出しておく。*/
  fontMgr_GetFontSetInfo
    ( w->offthespotWin.fontset, 
      &w->offthespotWin.font_height, &w->offthespotWin.font_ascent ) ;
  fontMgr_GetFontSetInfo
    ( w->offthespotWin.minibuf_fontset, 
      &w->offthespotWin.mfont_height, &w->offthespotWin.mfont_ascent ) ;

  /* 編集用のバッファの確保。*/
  skkinput_bufferInit( &( w->offthespotWin.buffer ) ) ;
  /*w->offthespotWin.buffer.overthespot_like_input = True ;*/
  w->offthespotWin.buffer.redraw = OFFW_RedrawScreen ;

  /* まあ、Focus は最初は外れていると思うよ。*/
  w->offthespotWin.is_focus = False ;

  /* Off-the-spot Window として機能させるために必要な変数の初期化。*/
  w->offthespotWin.focus_window  = None ;
  w->offthespotWin.input_focus_window = None ;
  w->offthespotWin.spot_x = w->offthespotWin.spot_y = 0 ;
  w->offthespotWin.focus_offset_x =
    w->offthespotWin.focus_offset_y = 0 ;
  /* 変換クライアントの表示領域の初期化をしておく。*/
  w->offthespotWin.client_area.x = 
    w->offthespotWin.client_area.y = 0 ;
  w->offthespotWin.client_area.height = 
    w->offthespotWin.client_area.width = 0 ;
  /* ステータス領域の初期化を行う。*/
  w->offthespotWin.status_area.x =
    w->offthespotWin.status_area.y = 0 ;
  w->offthespotWin.status_area.height = 
    w->offthespotWin.status_area.width = 0 ;

  /* バッファの中身を表示するために使うウィンドウを消去しておく。*/
  w->offthespotWin.canvas_probe = False ;
  w->offthespotWin.minibuffer_probe = False ;
  w->offthespotWin.modeshell_probe = False ;

  w->offthespotWin.attribute_mask = 0L ;
  /* カーソルの大きさの設定。*/
  w->offthespotWin.cursor_width = 8 ;
  /* history の初期化をする。*/
  OFFW_InitializeHistory( gnew ) ;

  w->offthespotWin.modeshell_win =
    w->offthespotWin.canvas_win = None ;
  w->offthespotWin.modeshell_width = w->offthespotWin.modeshell_height = 1 ;
  w->offthespotWin.modeshell_border_width = 2 ;
  return ;
}

static void OFFW_ReleaseAllGCs( Widget gw )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  if( w->offthespotWin.gc != NULL )
    XFreeGC( XtDisplay( gw ), w->offthespotWin.gc ) ;
  if( w->offthespotWin.rgc != NULL )
    XFreeGC( XtDisplay( gw ), w->offthespotWin.rgc ) ;
  w->offthespotWin.gc = w->offthespotWin.rgc = NULL ;
  return ;
}

static void OFFW_ReleaseMinibufferGCs( Widget gw )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  if( w->offthespotWin.minibuf_gc != NULL )
    XFreeGC( XtDisplay( gw ), w->offthespotWin.minibuf_gc ) ;
  if( w->offthespotWin.minibuf_rgc != NULL )
    XFreeGC( XtDisplay( gw ), w->offthespotWin.minibuf_rgc ) ;
  w->offthespotWin.minibuf_gc = w->offthespotWin.minibuf_rgc = NULL ;
  return ;
}

static void OFFW_FreeFontSet( Widget gw )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  int i ;

  for( i = 0 ; i < NUMBER_OF_CHARSET ; i ++ ){
    fontMgr_FreeFont
      ( XtDisplay( gw ), w->offthespotWin.fontset[ i ] ) ;
    fontMgr_FreeFont
      ( XtDisplay( gw ), w->offthespotWin.minibuf_fontset[ i ] ) ;
    w->offthespotWin.fontset[ i ] = 
      w->offthespotWin.minibuf_fontset[ i ] = NULL ;
  }
  return ;
}

static void OFFW_CreateAllGCs( Widget gw )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  XGCValues gcvalues ;

  gcvalues.foreground = w->offthespotWin.oforeground ;
  gcvalues.background = w->offthespotWin.obackground ;
  w->offthespotWin.gc = XCreateGC
    ( XtDisplay( gw ), w->offthespotWin.focus_window,
      GCForeground | GCBackground, &gcvalues ) ;

  gcvalues.background = w->offthespotWin.oforeground ;
  gcvalues.foreground = w->offthespotWin.obackground ;
  w->offthespotWin.rgc = XCreateGC
    ( XtDisplay( gw ), w->offthespotWin.focus_window,
      GCForeground | GCBackground, &gcvalues ) ;
  return ;
}

static void OFFW_CreateMinibufferGCs( Widget gw )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  XGCValues gcvalues ;

  gcvalues.foreground = w->offthespotWin.foreground ;
  gcvalues.background = w->offthespotWin.background ;
  w->offthespotWin.minibuf_gc = XCreateGC
    ( XtDisplay( gw ), XtWindow( w->offthespotWin.minibuffer_canvas ),
      GCForeground | GCBackground, &gcvalues ) ;

  gcvalues.background = w->offthespotWin.foreground ;
  gcvalues.foreground = w->offthespotWin.background ;
  w->offthespotWin.minibuf_rgc = XCreateGC
    ( XtDisplay( gw ), XtWindow( w->offthespotWin.minibuffer_canvas ),
      GCForeground | GCBackground, &gcvalues ) ;
  return ;
}

static Window OFFW_CreateSubCanvas
( Widget gw, Window focus_window, int *probe, int border_width )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  Window win ;

  if( border_width <= 0 ){
    win = XCreateSimpleWindow
      ( XtDisplay( gw ), focus_window, 0, 0, 1, 1, 0,
	w->offthespotWin.obackground,
	w->offthespotWin.obackground ) ;
  } else {
    win = XCreateSimpleWindow
      ( XtDisplay( gw ), focus_window, 0, 0, 1, 1, border_width,
	w->offthespotWin.oforeground,
	w->offthespotWin.obackground ) ;
  }
  add_myeventhandler
    ( XtDisplay( gw ), win, XtWindow( gw ), Expose, ExposureMask ) ;
  add_myeventhandler
    ( XtDisplay( gw ), win, XtWindow( gw ), KeyPress, KeyPressMask ) ;
  add_myeventhandler
    ( XtDisplay( gw ), win, XtWindow( gw ), KeyRelease, KeyReleaseMask ) ;
  add_myeventhandler
    ( XtDisplay( gw ), win, XtWindow( gw ), DestroyNotify, SubstructureNotifyMask ) ;
  /* 作りはしたものの必要になるまでは、map しない。*/
  *probe = False ;
  return win ;
}

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

  winwidth  = w->offthespotWin.minibuf_width ;
  if( w->offthespotWin.change_minibuffer_font ){
    winheight   = w->offthespotWin.font_height ;
    font_height = w->offthespotWin.font_height ;
  } else {
    winheight   = w->offthespotWin.mfont_height ;
    font_height = w->offthespotWin.mfont_height ;
  }
  minibuffer_popup = XtVaCreatePopupShell
    ( "minibuffer", wmcloseShellWidgetClass, gw,
	  XtNinput,				w->offthespotWin.m_fInputFocus,
      XtNmappedWhenManaged,	TRUE, 
      XtNwidth,				winwidth,
	  XtNheight,			winheight, 
      XtNcolormap,			gw->core.colormap, 
      XtNreverseVideo,		w->offthespotWin.reverse_video,
      XtNbackground,		w->offthespotWin.background,
      XtNforeground,		w->offthespotWin.foreground, NULL ) ;
  XtAddCallback (minibuffer_popup, XtNwmcloseNotify, (XtCallbackProc) OFFW_wmMessageCloseCallback, gw) ;
  XtAddCallback (minibuffer_popup, XtNdestroyNotify, (XtCallbackProc) OFFW_wmShellDestroyCallback, gw) ;

  /* その下につく表示用の widget を作成する。以前、shellwidget に直 *
   * 接書いてはまったことがあるので…。*/
  minibuffer_canvas = XtVaCreateManagedWidget
    ( "canvas", canvasWidgetClass, minibuffer_popup,
      XtNreverseVideo,		w->offthespotWin.reverse_video,
      XtNbackground,		w->offthespotWin.background,
      XtNforeground,		w->offthespotWin.foreground, NULL ) ;
  w->offthespotWin.minibuffer_probe = False ;
  /* 再描画イベントを奪っておく。*/
  XtAddCallback
    ( minibuffer_canvas, XtNredrawNotify,
      ( XtCallbackProc )Minibuffer_RedisplayCallback, gw ) ;
  XtAddCallback
    ( minibuffer_canvas, XtNdestroyNotify, 
      ( XtCallbackProc )Canvas_DestroyCallback, gw ) ;

  /* 先にミニバッファの情報を渡しておく。realize してから入れると危険。*/
  w->offthespotWin.minibuffer_popup  = minibuffer_popup ;
  w->offthespotWin.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      = winwidth + sizehints.base_width ;
  sizehints.height     = winheight + sizehints.base_height ;
  sizehints.width_inc  = 1 ;
  sizehints.height_inc = font_height ;
  sizehints.min_width  = sizehints.base_width ;
  sizehints.min_height = winheight + sizehints.base_height ;
  sizehints.flags      =
    ( PBaseSize | PMinSize | PResizeInc | USSize | PWinGravity ) ;

  /* Window Manager にヒントを送っている。*/
  XSetWMNormalHints
    ( XtDisplay( gw ), XtWindow( minibuffer_popup ), &sizehints ) ;
  /*XFlush( XtDisplay( gw ) ) ;*/
  return ;
}

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

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

	/* 変換クライアントが指定されていない、もしくは、フォントの設定が間
	 * 違っている場合には起動しない。*/
	if( w->offthespotWin.client_window == None ){
		XtDestroyWidget( gw ) ;
		return ;
	}

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

	if( w->offthespotWin.focus_window == None ){
		w->offthespotWin.focus_window = w->offthespotWin.client_window ;
		/* フォーカス先のウィンドウの情報が来ていないのなら、自前で用意する。*/
		if( !( w->offthespotWin.attribute_mask & CAClientArea ) )
			XGetRectangleOfWindow
				( XtDisplay( gw ), w->offthespotWin.focus_window, 
				  &w->offthespotWin.client_area ) ;
		OFFW_ReconfigureFocusPosition( gw ) ;
	}
	/* ここでやっと、gc を作ることができる。*/
	OFFW_CreateAllGCs( gw ) ;
	
	/* Minibuffer を作成する。*/
	OFFW_RealizeMinibuffer( gw ) ;
	OFFW_CreateMinibufferGCs( gw ) ;
	
	/* modeshell 表示のためのウィジェットを作成する。*/
	w->offthespotWin.modeshell_win = OFFW_CreateSubCanvas
		( gw, w->offthespotWin.client_window, 
		  &w->offthespotWin.modeshell_probe, 0 ) ;
	w->offthespotWin.modeshell_width  = 1 ;
	w->offthespotWin.modeshell_height = 1 ;
	/* 本文描画用のキャンバスは3つ必要になる。こちらはフォーカスウィンド
	   ウにはりつくことになる。*/
	w->offthespotWin.canvas_win = OFFW_CreateSubCanvas
		( gw, w->offthespotWin.client_window, 
		  &w->offthespotWin.canvas_probe, 0 ) ;
	XMoveResizeWindow
		( XtDisplay( gw ), w->offthespotWin.canvas_win,
		  w->offthespotWin.client_area.x, w->offthespotWin.client_area.y,
		  w->offthespotWin.client_area.width,
		  w->offthespotWin.client_area.height ) ;
     
	/* フォーカスを設定するのなら、focus が変化した時に利用するすべての */
	/* ウィジェットがrealizeした後でなければならない。*/
	if (w->offthespotWin.m_fInputFocus) {
		XtSetKeyboardFocus( w->offthespotWin.minibuffer_popup, gw ) ;
		XtSetKeyboardFocus( w->offthespotWin.minibuffer_canvas, gw ) ;
	}
	
	/*
	 * この位置ならモードシェルを作成しても問題ない。
	 */
	OFFW_resetupModeWindow (gw) ;
	OFFW_ReconfigureColor (gw, CAForegroundPixel | CABackgroundPixel | CAColormap) ;
	
	XMapWindow (XtDisplay (gw), w->offthespotWin.canvas_win) ;
	w->offthespotWin.canvas_probe = True ;
	return ;
}

/*
 * SIW に XtDestroyWidget をかけた時に呼び出される関数。
 *-----
 * SIW の終了処理一揃えが入っている。GC を解放してから、malloc してい
 * たメモリを解放している。
 */
static void OFFW_Destroy( Widget gw )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  struct SKKInputNode *node, *pNode ;
  /*
   * XFreeFont( XtDisplay( gw ), w->offthespotWin.fs_kanji ) ;
   * XFreeFont( XtDisplay( gw ), w->offthespotWin.fs_roman ) ;
   * どうやら、Widget 毎に確保しているわけじゃないみたいなので、ここで
   * 解放するとはまるみたいだ。
   */
  /* Destroy した以上、以下のウィンドウのイベントは全部無視する。*/
  XSafeSelectInput( XtDisplay( gw ), XtWindow( gw ), NoEventMask ) ;
  remove_allmyeventhandler
    ( XtDisplay( gw ), w->offthespotWin.modeshell_win ) ;
  remove_allmyeventhandler
    ( XtDisplay( gw ), w->offthespotWin.canvas_win ) ;
  XSafeSelectInput
    ( XtDisplay( gw ), XtWindow( w->offthespotWin.minibuffer_popup ),
      NoEventMask ) ;
  XSafeSelectInput
    ( XtDisplay( gw ), XtWindow( w->offthespotWin.minibuffer_canvas ),
      NoEventMask ) ;
  /* Event Queue をフラッシュしておく。*/
  XSafeFlush( XtDisplay( gw ) ) ;

  OFFW_ReleaseAllGCs( gw ) ;
  OFFW_ReleaseMinibufferGCs( gw ) ;
  OFFW_FreeFontSet( gw ) ;

  /* ウィンドウを破棄する。*/
  if( w->offthespotWin.modeshell_win != None )
    XDestroyWindow( XtDisplay( gw ), w->offthespotWin.modeshell_win ) ;
  if( w->offthespotWin.canvas_win != None )
    XDestroyWindow( XtDisplay( gw ), w->offthespotWin.canvas_win ) ;

  /*
   * ヒストリを親へと返す。
   */
  if( w->offthespotWin.historyAttribute != NULL ){
    /* ヒストリについて親に返します。*/
    w->offthespotWin.historyAttribute->history_start =
      w->offthespotWin.buffer.hist_start ;
    w->offthespotWin.historyAttribute->history_end =
      w->offthespotWin.buffer.hist_end ;
    /* その場変換モードの状況について親へと返す。*/
    w->offthespotWin.historyAttribute->overthespot_like_input =
      w->offthespotWin.buffer.overthespot_like_input ;
    /* まあ…その仮名モードの状況を親へと返します。*/
    if( w->offthespotWin.buffer.topbuffer != NULL ){
      w->offthespotWin.historyAttribute->j_mode =
	w->offthespotWin.buffer.topbuffer->j_mode ;
      w->offthespotWin.historyAttribute->j_zenkaku =
	w->offthespotWin.buffer.topbuffer->j_zenkaku ;
      w->offthespotWin.historyAttribute->j_katakana_mode =
	w->offthespotWin.buffer.topbuffer->j_katakana_mode ;
    }
  }
  /*
   * バッファを全て解放しておく。
   */
  node = w->offthespotWin.buffer.lastbuffer ;
  while( node != NULL ){
    pNode = node->parentbuffer ;
    free_Minibuffer( gw, &( w->offthespotWin.buffer ), node ) ;
    node  = pNode ;
  }
  XtCallCallbacks( gw, XtNendNotify, w->offthespotWin.historyAttribute ) ;
  w->offthespotWin.historyAttribute = NULL ;
  return ;
}

/*
 * 画面を再描画する関数。
 */
static void OFFW_Redisplay( Widget gw, XEvent *event, Region region )
{
#if 0
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  /* これは何かのタイミングで間違った Widget の再描画が送られている。*/
  if( w->offthespotWin.buffer.topbuffer == NULL ||
      w->core.being_destroyed ){
#if defined(DEBUG)
    fprintf( stderr, "Illegal Widget Exposure Event.\n" ) ;
#endif
    return ;
  }
#endif
  OFFW_RedrawScreen( gw ) ;
/*  XFlush( XtDisplay( gw ) ) ;*/
  return ;
}

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

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

  OFFW_RedrawScreen( gw ) ;
  w->offthespotWin.camsg = NULL ;
  return True ;
}

static void OFFW_ResizeMinibufferAndModeshell( Widget gw )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  XSizeHints sizehints ;

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

/*
 * 変換クライアントの前景色及び背景色、カラーマップが変更されたために、
 * GC の再設定を行う関数。
 */
static void OFFW_ReconfigureColor( Widget gw, unsigned long valuemask )
{
	OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
	unsigned long mask ;
	XSetWindowAttributes xswa ;

	mask = 0L ;
	if (valuemask & (CAForegroundPixel | CABackgroundPixel)) {
		mask |= ( CWBackPixel | CWBorderPixel ) ;
		xswa.background_pixel = w->offthespotWin.obackground ;
		xswa.border_pixel     = w->offthespotWin.oforeground ;
	}
	/* カラーマップが変更されたのですか？ */
	if( valuemask & CAColormap ){
		mask |= CWColormap ;
		xswa.colormap = w->offthespotWin.colormap ;
	}
	if( mask ){
		XChangeWindowAttributes
			( XtDisplay( gw ), w->offthespotWin.modeshell_win, 
			  mask, &xswa ) ;
		XChangeWindowAttributes
			( XtDisplay( gw ), w->offthespotWin.canvas_win, 
			  mask, &xswa ) ;
	}
	/* 色の変更がなかったら、GC は作り直さなくて良い？ しかし、カラーマッ
	   プはどうするのだろう？ */
	if (! (valuemask & (CAForegroundPixel | CABackgroundPixel)))
		return ;

	if (XtIsRealized (gw)){
		/* まず、今迄使っていた GC を全て解放する。う？ minibuffer の色って *
		 * 変更すべきかな？  */
		OFFW_ReleaseAllGCs( gw ) ;
		OFFW_CreateAllGCs( gw ) ;
	}
	return ;
}

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

  /* 辞書が修正されていたら、書き直しを実行する。*/
  if( curw->offthespotWin.buffer.jisyo_dirty !=
      reqw->offthespotWin.buffer.jisyo_dirty ){
    neww->offthespotWin.buffer.jisyo_dirty =
      reqw->offthespotWin.buffer.jisyo_dirty ;
    /* 窓が起きていなければ実行しないぞ、と。*/
    if( neww->offthespotWin.modeshell_probe ){
      Modeshell_Redisplay
	( new, neww->offthespotWin.modeshell_win ) ;
    }
    return False ;
  }
  /* 変換属性の修正要求が来た場合と見付けたり。*/
  if( reqw->offthespotWin.camsg != NULL ){
    int ret ;
    /* 変換属性を修正する…本当にこれで言葉足りるのかどうかは不明。 *
     * やってみるっきゃないね！                                     *
     * 若葉：「そうですね。やってみましょう、…さん！」             */
    camsg = reqw->offthespotWin.camsg ;
    reqw->offthespotWin.camsg = neww->offthespotWin.camsg = 
      curw->offthespotWin.camsg = NULL ;

    ret = OFFW_ChangeAttributes
      ( new, camsg->mask, &camsg->value ) ;

    if( XtIsRealized( new ) )
      OFFW_ReconfigureWindows( new ) ;
    return ret ;
  }
  /* ミニバッファを消去したいという要望を受けた時の処理を行う。*/
  if( reqw->offthespotWin.clearMinibuffer ){
    if( curw->offthespotWin.minibuffer_probe ){
      XtPopdown( curw->offthespotWin.minibuffer_popup ) ;
      curw->offthespotWin.minibuffer_probe =
	neww->offthespotWin.minibuffer_probe = False ;
    }
    reqw->offthespotWin.clearMinibuffer =
      neww->offthespotWin.clearMinibuffer = 
      curw->offthespotWin.clearMinibuffer = False ;
    return FALSE ;
  }
  /* ポップアップする。*/
  if( reqw->offthespotWin.conversion_set_focus ){
    reqw->offthespotWin.conversion_set_focus = 
      neww->offthespotWin.conversion_set_focus = 
      curw->offthespotWin.conversion_set_focus = False ;
    if( !neww->offthespotWin.modeshell_probe ){
      XMapWindow( XtDisplay( new ), neww->offthespotWin.modeshell_win ) ;
      neww->offthespotWin.modeshell_probe = True ;
    }
    if( !neww->offthespotWin.canvas_probe ){
      XMapWindow( XtDisplay( new ), neww->offthespotWin.canvas_win ) ;
      neww->offthespotWin.canvas_probe = True ;
    }
    /* ミニバッファが起きていたかもしれないので復活させる。*/
    OFFW_ConfigureMinibuffer( new ) ;
    return FALSE ;
  }
  /* ポップダウンする。*/
  if( reqw->offthespotWin.conversion_unset_focus ){
    reqw->offthespotWin.conversion_unset_focus = 
      neww->offthespotWin.conversion_unset_focus = 
      curw->offthespotWin.conversion_unset_focus = False ;
    if( neww->offthespotWin.modeshell_probe ){
      XUnmapWindow( XtDisplay( new ), neww->offthespotWin.modeshell_win ) ;
      neww->offthespotWin.modeshell_probe = False ;
    }
    if( neww->offthespotWin.canvas_probe ){
      XUnmapWindow( XtDisplay( new ), neww->offthespotWin.canvas_win ) ;
      neww->offthespotWin.canvas_probe = False ;
    }
    return FALSE ;
  }
  return( FALSE ) ;
}

static int OFFW_ReconfigureFocusPosition
( Widget gw )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  int x, y, ofx, ofy ;
  Window dummy ;
  int ret = False ;

  /* クライアントウィンドウのルートウィンドウの中での座標を求める。*/
  XTranslateCoordinates
    ( XtDisplay( gw ), w->offthespotWin.client_window,
      RootWindowOfScreen( XtScreen( gw ) ),
      0, 0, &x, &y, &dummy ) ;
  if( w->offthespotWin.focus_window != w->offthespotWin.client_window &&
      w->offthespotWin.focus_window != None ){
    /* フォーカスウィンドウのクライアントウィンドウの中での座標を求める。*/
    XTranslateCoordinates
      ( XtDisplay( gw ), w->offthespotWin.focus_window,
	w->offthespotWin.client_window, 
	0, 0, &ofx, &ofy, &dummy ) ;
  } else {
    ofx = ofy = 0 ;
  }
  /* クライアントウィンドウのルートウィンドウの中での座標を記憶しておく。*/
  if( w->offthespotWin.client_x != x || w->offthespotWin.client_y != y ){
    w->offthespotWin.client_x = x ;
    w->offthespotWin.client_y = y ;
    ret = True ;
  }
  /* フォーカスウィンドウのクライアントウィンドウの中での座標を記憶しておく。*/
  if( w->offthespotWin.focus_offset_x != ofx ||
      w->offthespotWin.focus_offset_y != ofy ){
    w->offthespotWin.focus_offset_x = ofx ;
    w->offthespotWin.focus_offset_y = ofy ;
    ret = True ;
  }
  return ret ;
}

/*
 * いきなり起動している段階でフォーカスを移動せい！とかいう無茶苦茶な
 * 御願い(命令の間違いじゃないのか？)を何とかする関数。 
 *----
 * Netscape がそういう要求を出してくれるので、作りました。そう。世の中
 * の人にとっては、Netscape が全て。Netscape の日本語化がまずくて、Bus 
 * Error で落ちれば、それは全部 kinput2 や skkinput のせいなの。ああ、
 * 何てことかしら。わたくし悲しいですわ。（笑）
 */
static void OFFW_ChangeFocusWindow
( Widget gw, Window focus_win )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;

  /* focus window にはりついていたウィンドウを全て破棄する。*/
  XDestroyWindow( XtDisplay( gw ), w->offthespotWin.canvas_win ) ;
  w->offthespotWin.canvas_win = OFFW_CreateSubCanvas
    ( gw, focus_win, &w->offthespotWin.canvas_probe, 0 ) ;

  XDestroyWindow( XtDisplay( gw ), w->offthespotWin.modeshell_win ) ;
  w->offthespotWin.modeshell_win = OFFW_CreateSubCanvas
    ( gw, focus_win, &w->offthespotWin.modeshell_probe, 
      w->offthespotWin.modeshell_border_width ) ;

  w->offthespotWin.focus_window = focus_win ;
  OFFW_ReleaseAllGCs( gw ) ;
  OFFW_CreateAllGCs( gw ) ;
  return ;
}

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

	if( valuemask & CAFocusWindow ){
#ifdef DEBUG
		fprintf ( stderr, "Get focus window (%ld)\n", values->focus_window ) ;
#endif
		/* フォーカス先の窓って実在するの？ とか実はもう少しきっちりと *
		 * 見る必要があると思う。*/
		if( values->focus_window != None ){
			/* 一度設定した筈のフォーカスが別物になっていたら、不味いんでは */
			/* ないかい？ という話です。*/
			if( w->offthespotWin.focus_window != None ){
				OFFW_ChangeFocusWindow( gw, values->focus_window ) ;
				w->offthespotWin.attribute_mask &= ~( CAStatusArea ) ;
			} else {
				w->offthespotWin.focus_window = values->focus_window ;
			}
			/* 変換クライアントの領域に対する情報が無かったら自前で用意して *
			 * おく。*/
			if( !(( w->offthespotWin.attribute_mask ) & CAClientArea )){
				XGetRectangleOfWindow
					( XtDisplay( gw ), w->offthespotWin.focus_window, 
					  &w->offthespotWin.client_area ) ;
			}
			/* ステータス領域が指定されていなかったら、とりあえずはクライア
			   ント領域を用いる。ただし、このままでは絶対に見栄えは腐るので
			   アプリケーション側が何とかすること。*/
			if( !(( w->offthespotWin.attribute_mask ) & CAStatusArea ) ){
				w->offthespotWin.status_area = w->offthespotWin.client_area ; 
			}
			OFFW_ReconfigureFocusPosition( gw ) ;
			ret = True ;
		}
	}
	if( valuemask & CAStatusArea ){
		/* 座標の修正があった、もしくは表示領域が修正されている場合。*/
		if( values->status_area.x != w->offthespotWin.status_area.x ||
			values->status_area.y != w->offthespotWin.status_area.y ||
			values->status_area.width  != w->offthespotWin.status_area.width || 
			values->status_area.height != w->offthespotWin.status_area.height ){
			w->offthespotWin.status_area.x = values->status_area.x ;
			w->offthespotWin.status_area.y = values->status_area.y ;
			w->offthespotWin.status_area.width  = values->status_area.width ;
			w->offthespotWin.status_area.height = values->status_area.height ;
			w->offthespotWin.attribute_mask |= CAStatusArea ;
			ret = True ;
		}
	}
	rec_col = False ;
	/* カラーマップの変更要求が来た場合。*/
	if( ( valuemask & CAColormap ) &&
		w->offthespotWin.colormap != values->colormap ){
		w->offthespotWin.colormap = values->colormap ;
		rec_col = True ;
	}
	/* 背景色、前景色の変更要求が来た場合。*/
	if ((valuemask & CAForegroundPixel) &&
		w->offthespotWin.oforeground != values->foreground){
		w->offthespotWin.oforeground = values->foreground ;
		rec_col = True ;
	}
	if ((valuemask & CABackgroundPixel) &&
		w->offthespotWin.obackground != values->background) {
		w->offthespotWin.obackground = values->background ;
		rec_col = True ;
	}
	if( XtIsRealized( gw ) && rec_col ){
		OFFW_ReconfigureColor( gw, valuemask ) ;
		ret = True ;
	}
	/* 変換クライアントの表示領域の修正通知が来た場合の処理。*/
	if( valuemask & CAClientArea ){
		/* 座標の修正があった、もしくは表示領域が修正されている場合。*/
		if( values->client_area.x != w->offthespotWin.client_area.x ||
			values->client_area.y != w->offthespotWin.client_area.y ||
			values->client_area.width != w->offthespotWin.client_area.width || 
			values->client_area.height != w->offthespotWin.client_area.height ){
			/* 変換クライアントの表示領域の変更を覚えておく。*/
			w->offthespotWin.client_area    = values->client_area ;
#ifdef DEBUG
			fprintf( stderr, "Get client area pos:(%d,%d), size:%d x %d.\n",
					 w->offthespotWin.client_area.x,
					 w->offthespotWin.client_area.y,
					 w->offthespotWin.client_area.width,
					 w->offthespotWin.client_area.height ) ;
#endif
			w->offthespotWin.attribute_mask |= CAClientArea ;
			ret = True ;
		}
	}
	/* 座標を修正せよという要求が来ていた場合の処理を行う。*/
	if( valuemask & CASpotLocation ){
		if( w->offthespotWin.focus_window != None ){
			int prev_focus ;
#if defined(DEBUG)
			fprintf( stderr, "CASPOT nanode FOCUSWINDOW miru (%ld).\n",
					 w->offthespotWin.focus_window ) ;
#endif
			prev_focus = w->offthespotWin.is_focus ;
			w->offthespotWin.is_focus = focusCheck( gw ) ;
			if( prev_focus != w->offthespotWin.is_focus ){
				ret = True ;
			}
		}
		OFFW_ReconfigureFocusPosition( gw ) ;
		if( values->spot_x != w->offthespotWin.spot_x ||
			values->spot_y != w->offthespotWin.spot_y ){
#ifdef DEBUG
			fprintf( stderr, "Get Basho Shitei meirei.\n" ) ;
#endif
			w->offthespotWin.spot_x = values->spot_x ;
			w->offthespotWin.spot_y = values->spot_y ;
			ret = True ;
		}
	}
	/* フォント情報の修正があった場合の処理。*/
	if( valuemask & CAFonts ){
#ifdef DEBUG
		fprintf( stderr, "FONT WO KIRIKAERU.\n" ) ;
#endif
		/* フォント情報を更新する。この時クライアント側のフォントの情報に
		 * 全て合わせるものとする。例え、クライアントが補助漢字フォントを
		 * 指定してくれなくてデフォルトのフォントを使うことになり、そのフォ
		 * ントの高さが合わなくても…。(見栄えのため) */
		if( fontMgr_GetFontSetInfo
			( values->fontset,
			  &w->offthespotWin.font_height,
			  &w->offthespotWin.font_ascent ) ){
			/* フォントセットをコピーする。*/
			fontMgr_CopyFontSet
				( XtDisplay( gw ), w->offthespotWin.fontset, values->fontset ) ;
			/* ミニバッファとモードシェルの大きさを修正する。*/
			if( XtIsRealized( gw ) )
				OFFW_ResizeMinibufferAndModeshell( gw ) ;
			ret = True ;
		}
	}
	/* フォントの高さに関する制約が送られて来ている場合には…。*/
	if( valuemask & CALineSpacing ){
		if( values->linespacing > 0 ){
			w->offthespotWin.font_height = values->linespacing ;
			ret = True ;
		}
	}
	return ret ;
}

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

  if( commonKeyEventHandler( gw, xevent, &( w->offthespotWin.buffer ) ) )
    OFFW_RedrawScreen( gw ) ;
  return ;
}

/*
 * 現在マウスがフォーカスされているかどうかをチェックするための関数。
 *-----
 * 現在知られているバグとして、フォーカスの移動を非常に上手くすると、
 * Pointer が存在していることを見逃してしまうことがある…。こんなん分
 * かるかい！
 */
static int focusCheck( Widget gw )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  Window mouse_focus, rootwin, childwin ;
  int ret_focus_state ;
  int rootx, rooty, winx, winy ;
  unsigned int winmask ;
  
  /* まずマウスのフォーカスを奪っている人を見付ける。*/
  XGetInputFocus
    ( XtDisplay( gw ), &mouse_focus, &ret_focus_state ) ;

#if defined(DEBUG)
  fprintf( stderr, "Mouse Focus Window:(%ld)\n", mouse_focus ) ;
#endif
  if( mouse_focus == None || mouse_focus == PointerRoot )
    return False ;

  if( w->offthespotWin.input_focus_window != None ){
    if( mouse_focus == w->offthespotWin.input_focus_window )
      return True ;
  } 
  if( XQueryPointer
     ( XtDisplay( gw ), mouse_focus,
       &rootwin, &childwin, &rootx, &rooty, &winx, &winy, 
       &winmask ) ){
#if defined(DEBUG)
    fprintf
      ( stderr, "Focus Root Window:(%ld), Focus Child Window:(%ld)\n",
        rootwin, childwin ) ;
#endif
    /* 変換クライアントがマウスのフォーカスを持っている、もしく */
    /* はその子供がマウスのフォーカスを持っているのなら True */
    if( w->offthespotWin.focus_window == childwin ){
      if( w->offthespotWin.input_focus_window == None ){
	w->offthespotWin.input_focus_window = mouse_focus ;
      }
      return True ;
    }
    if( w->offthespotWin.focus_window == mouse_focus )
      return True ;
    /* ミニバッファウィンドウが開いている場合もあり得るよ。*/
    if( w->offthespotWin.minibuffer_probe ){
      Window win = XtWindow( w->offthespotWin.minibuffer_popup ) ;
      if( win == childwin || win == mouse_focus )
	return True ;
    }
  }
  return False ;
}

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

  /* フォーカスウィンドウも決まってないのに。そんなフォーカスIN なんて */
  /* 言ってる場合じゃない。*/
  if( w->offthespotWin.focus_window == None )
    return ;
  /* まずはフォーカスを失ったものと考える。*/
  prev_focus = w->offthespotWin.is_focus ;
  w->offthespotWin.is_focus = focusCheck( gw ) ;
  /* 画面の修正…カーソルの形状が変化するので。*/
  if( prev_focus != w->offthespotWin.is_focus )
    OFFW_RedrawScreen( gw ) ;
  return ;
}

/*
 * 以下のファイルは、OffthespotWinWidget のソースの一部である。
 */

/*
 * skkinput の窓を表示する関数。
 *-----
 * こちらは差分描画を行わない。
 */
static void OFFW_FullDrawWindow
( Display *disp, Window win, struct skkinputManagedFont **fontset,
  GC gc, GC rgc, int start_pos, int x, int y, int width, int height, 
  struct SKKInputNode *node, struct myChar *text, 
  int cursor_width, int font_height, int font_ascent, int is_focus )
{
  int pos, cursor_flag ;
  int cx, cy ;
  int xdiff ;

  pos         = start_pos ;
  cursor_flag = False ;

  cx = cy = 0 ;

  while( !IS_END_OF_STRING( *text ) ){
    xdiff = myCharTextWidth( fontset, text, 1 ) ;
    /* カーソルを表示する場所なのかどうかを判定する。*/
    if( pos == node->cur_pos ){
      if( node->cur_exist ){
	skkinputDrawCursor
	  ( disp, win, gc, rgc,
	    x, y, font_ascent, xdiff, font_height, is_focus ) ;
	cursor_flag = True ;
      }
      cx = x ;
      cy = y ;
    }
    /* 画面の右端まで描画したのかどうかを判断する。*/
    if( ( x + xdiff ) >= width ){
      XDrawLine( disp, win, gc, x, y, width, y + font_height ) ;
      x = 0 ;
      y += font_height ;
      /* 画面の下まで書き切ったのかどうかを判断する。*/
      if( y >= height )
	goto exit_loop ;
    }
    if( IS_ASCII_EQUAL( *text, '\n' ) ){
      /* 改行コードを発見した場合の処理。*/
      x =  0 ;
      y += font_height ;
      /* 画面の下まで書き切ったのかどうかを判断する。*/
      if( y >= height )
	goto exit_loop ;
    } else {
      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 ;
    }
    text ++ ;
    pos ++ ;
  }
  /* 最後までカーソルが表示されていなかったのなら、最後の行にカーソ *
   * ルを表示する。*/
  if( pos == node->cur_pos && node->cur_exist ){
    /* カーソル改行の必要あり？ */
    if( ( x + cursor_width ) > width ){
      skkwin_jputchar
	( disp, win, fontset, gc, x, y, '\\', False ) ;
      x  = 0 ;
      y += font_height ;
    }
    skkinputDrawCursor
      ( disp, win, gc, rgc, x, y, font_ascent, 
	cursor_width, font_height, is_focus ) ;
    cx = x ;
    cy = y ;
  }

exit_loop:
  node->prev_cx = cx ; 
  node->prev_cy = cy ;
  return ;
}
/*
 * モードウィンドウを正しい位置に移動させた挙句、中身まできちんと表示
 * してしまうという盛沢山な関数。
 */
static void OFFW_resetupModeWindow( Widget gw )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  int x, y, modeshell_width, modeshell_height ;

  /* はる位置については諸説色々あるだろうが左上(NorthWest)に固定してお
     く。*/
  x = w->offthespotWin.status_area.x ;
  y = w->offthespotWin.status_area.y ;

  /* modeshell の大きさを正す。*/
  modeshell_width  = getWidthOfModeLine
    ( w->offthespotWin.fontset,
      w->offthespotWin.buffer.topbuffer,
      w->offthespotWin.buffer.jisyo_dirty,
      w->offthespotWin.buffer.overthespot_like_input ) ;
  modeshell_height = w->offthespotWin.font_height ;

  /* 大きさが正しいものであるかどうかを判断する。*/
  if( w->offthespotWin.modeshell_width != modeshell_width ||
      w->offthespotWin.modeshell_height != modeshell_height ){
    w->offthespotWin.modeshell_width  = modeshell_width ;
    w->offthespotWin.modeshell_height = modeshell_height ;
    XResizeWindow
      ( XtDisplay( gw ), w->offthespotWin.modeshell_win,
	modeshell_width, modeshell_height ) ;
  }
  if( XtIsRealized( gw ) ){
    /* モードウィンドウが存在していなかったら作ってしまう。*/
    if( !w->offthespotWin.modeshell_probe ){
      w->offthespotWin.modeshell_probe = True ;
      XMoveWindow( XtDisplay( gw ), w->offthespotWin.modeshell_win, x, y ) ;
      XMapWindow( XtDisplay( gw ), w->offthespotWin.modeshell_win ) ;
    } else {
      /* 表示位置の修正をする。*/
      XMoveWindow
	( XtDisplay( gw ), w->offthespotWin.modeshell_win, x, y ) ;
    }
    /* モードラインを表示する。*/
    Modeshell_Display( gw, w->offthespotWin.modeshell_win ) ;
  }
  return ;
}

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

  /* 再描画させる。*/
  if( w->offthespotWin.canvas_probe )
    Canvas_Redisplay( gw, w->offthespotWin.canvas_win ) ;
  /* モードウィンドウを表示する。*/
  OFFW_resetupModeWindow( gw ) ;
  /* mini-buffer を表示する。*/
  OFFW_ConfigureMinibuffer( gw ) ;
  return ;
}

/* ここで、その位置が画面外に出るのかどうかを判断しなければなら *
 * ない。*/
static void OFFW_ConfigureMinibufferPosition
( Widget gw, int *rx, int *ry )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  XWindowAttributes xwa ;
  int x, y, mwidth, mheight ;
  int win_gravity ;
  XSizeHints sizehints ;

  win_gravity = NorthWestGravity ;

  /* Root Window の大きさを求めておく。*/
  XGetWindowAttributes
    ( XtDisplay( gw ), RootWindowOfScreen( XtScreen( gw ) ), &xwa ) ;
      
  /* もうちょっときちんとする必要あり。*/
  y = w->offthespotWin.client_y + w->offthespotWin.focus_offset_y + 
    w->offthespotWin.status_area.height +
    w->offthespotWin.minibuffer_popup->core.border_width ;
  x = w->offthespotWin.client_x + w->offthespotWin.focus_offset_x ;

  mheight = w->offthespotWin.minibuffer_popup->core.border_width * 2 +
    ( ( w->offthespotWin.change_minibuffer_font )?
      w->offthespotWin.font_height : w->offthespotWin.mfont_height ) ;
  mwidth = w->offthespotWin.minibuffer_popup->core.border_width * 2 +
    w->offthespotWin.minibuf_width ;

  if( y + mheight > xwa.height ){
    y = w->offthespotWin.client_y - mheight -
      w->offthespotWin.minibuffer_popup->core.border_width * 2 ;
    if( y < 0 ){
      y = xwa.height - mheight -
	w->offthespotWin.minibuffer_popup->core.border_width * 2 ;
    }
    if( y < 0 ){
      y = 0 ;
    } else {
      win_gravity = SouthWestGravity ;
    }
  }
  if( x + mwidth > xwa.width ){
    x = xwa.width - mwidth ;
    if( x < 0 ){
      x = 0 ;
    } else {
      if( win_gravity == NorthWestGravity ){
	win_gravity = NorthEastGravity ;
      } else {
	win_gravity = SouthEastGravity ;
      }
    }
  } else if( x < 0 ){
    x = 0 ;
  }
  /* Window Manager にヒントを送っている。ただし、XSetWMNormalHints * 
   * は部分書換えしないようなので、以前の hints を読みとってから差し*
   * 替えるという手法をとらなければならない。*/
  sizehints.flags = PWinGravity ;
  sizehints.win_gravity = win_gravity ;
  XChangeWMNormalHints
    ( XtDisplay( gw ),
      XtWindow( w->offthespotWin.minibuffer_popup ),
      &sizehints ) ;
  *rx = x ;
  *ry = y ;
  return ;
}

/*
 * ミニバッファウィンドウの配置、大きさの設定を行う関数。
 *----
 * 大きさは実は設定してません。最初に設定したきりです。画面の内にミニ
 * バッファ窓を何処に置いたら良いのかな…と判断するに使うわけです。
 */
static void OFFW_ConfigureMinibuffer( Widget gw )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  struct SKKInputNode *node = w->offthespotWin.buffer.topbuffer ;
  struct SKKInputNode *mNode = w->offthespotWin.buffer.lastbuffer ;

  if( mNode == node ){
    /* 表示すべきテキストが何も無かった場合には。*/
    if( IS_END_OF_STRING( node->mtextbuffer[ 0 ] ) ){
      /* ＰＯＰアップした状態だったら、閉じる。*/ 
      if( w->offthespotWin.minibuffer_probe ){
	XtPopdown( w->offthespotWin.minibuffer_popup ) ;
	w->offthespotWin.minibuffer_probe = False ;
      }
      return ;
    }
  }
  /* ミニバッファは起きていないの？ 起きていないのだったら起こす必要 *
   * があるよ。*/
  if( !w->offthespotWin.minibuffer_probe ){
    int x, y ;
    OFFW_ConfigureMinibufferPosition( gw, &x, &y ) ;

    /* 指定された位置にミニバッファを移動させる。*/
    XtMoveWidget
      ( w->offthespotWin.minibuffer_popup, x, y ) ;
    /* Popup する。*/
    XtPopup( w->offthespotWin.minibuffer_popup, XtGrabNone ) ;
    w->offthespotWin.minibuffer_probe = True ;
  }
  /* キャンバスを書き直すように要求を出す。*/
  XtVaSetValues
    ( w->offthespotWin.minibuffer_canvas, 
      XtNredrawRequest, True, NULL ) ;
  return ;
}    

static void Canvas_Redisplay
( Widget gw, Window win )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  int linenum, cur_line, maxline, spos, sty, edy ;
  struct myChar *ptr ;
  struct SKKInputNode *node = w->offthespotWin.buffer.topbuffer ;

  /* Canvas が popup していなければ却下する。popup するまでにフォント
     の初期化などをするので、以下の処理が実行されては困るわけである。*/
  if( !w->offthespotWin.canvas_probe )
    return ;

  XClearWindow( XtDisplay( gw ), win ) ;

  /* 最大表示可能行数を求める。*/
  maxline = w->offthespotWin.client_area.height /
    w->offthespotWin.font_height ;
  /* 現在、テキストは何行まで表示しなければならないのかを算出する。*/
  linenum = skkinput_GetLineNum
    ( w->offthespotWin.fontset, node->textbuffer,
      w->offthespotWin.client_area.width, w->offthespotWin.cursor_width,
      node->cur_pos, &cur_line ) ;
  /* 表示可能行数を超えていた場合の処理。カーソル位置が入る範囲の内 *
   * で一番最初の行の番号が最も小さいくなるように設定する。*/
  if( linenum >= maxline && cur_line >= maxline ){
    int startline = cur_line - maxline + 1 ;
    /* 指定された場所から表示しなればならないので、その位置を算出する。*/
    spos = skkinput_FindStartLine
      ( w->offthespotWin.fontset, node->textbuffer,
	startline, w->offthespotWin.client_area.width ) ;
    ptr = node->textbuffer + spos ;
  }  else {
    spos = 0 ;
    /* 共に一番最初の文字から表示可能である。*/
    ptr = node->textbuffer ;
  }    
  sty = w->offthespotWin.font_ascent ;
  edy = sty + maxline * w->offthespotWin.font_height ;
  /* Window の buffer に文字列を表示する。*/
  OFFW_FullDrawWindow
    ( XtDisplay( gw ), win,
      w->offthespotWin.fontset, 
      w->offthespotWin.gc, w->offthespotWin.rgc,
      spos, 0, sty, w->offthespotWin.client_area.width, edy, 
      node, ptr, w->offthespotWin.cursor_width, 
      w->offthespotWin.font_height, w->offthespotWin.font_ascent,
      w->offthespotWin.is_focus ) ;
  return ;
}

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

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

  if( w->offthespotWin.change_minibuffer_font ){
    fontset    = w->offthespotWin.fontset ;
    fontheight = w->offthespotWin.font_height ;
    fontascent = w->offthespotWin.font_ascent ;
  } else {
    fontset    = w->offthespotWin.minibuf_fontset ;
    fontheight = w->offthespotWin.mfont_height ;
    fontascent = w->offthespotWin.mfont_ascent ;
  }
  XClearWindow( XtDisplay( gw ), XtWindow( gw ) ) ;

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

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

    /* しつこくもみっともなくも必ず表に出てくるようにする。*/
    XRaiseWindow
      ( XtDisplay( gw ), XtWindow( gw ) ) ;
    skkwin_jputstring
      ( XtDisplay( gw ), XtWindow( gw ), 
	fontset, w->offthespotWin.minibuf_gc,
	0, fontascent, node->mtextbuffer ) ;
  } else {
    /* しつこくもみっともなくも必ず表に出てくるようにする。*/
    XRaiseWindow
      ( XtDisplay( gw ), XtWindow( gw ) ) ;

    if( !IS_END_OF_STRING( mNode->mtextbuffer[ 0 ] ) ){
      skkwin_jputstring
	( XtDisplay( gw ), XtWindow( gw ),
	  fontset, w->offthespotWin.minibuf_gc,
	  0, fontascent, mNode->mtextbuffer ) ;
    } else {
      struct myChar *toptext ;
      int toppos ;

      /* Window の buffer に文字列を表示する。*/
      OTSW_CalcTopPositionOfBuffer
	( fontset, mNode->textbuffer, 0, mNode->cur_pos, gw->core.width,
	  &toptext, &toppos ) ;
      OTSW_FullDrawTopBufferTopLine
	( XtDisplay( gw ), XtWindow( gw ), fontset, 
	  w->offthespotWin.minibuf_gc, w->offthespotWin.minibuf_rgc, 
	  toptext, toppos, fontascent, fontheight,
	  gw->core.width,
	  !IS_END_OF_STRING( mNode->textbuffer[ mNode->cur_pos ] ),
	  w->offthespotWin.cursor_width,
	  mNode->cur_pos, mNode->cur_exist, 
	  w->offthespotWin.is_focus ) ;
    }
  }
  return ;
}

/*
 * modeshell window にモードを表示をする関数。
 */
static void Modeshell_Display
( Widget gw, Window win )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  struct SKKInputNode *node = w->offthespotWin.buffer.topbuffer ;
  unsigned long mode_status ;

  /* モードウィンドウが存在していなかったら書かない。*/
  if( !w->offthespotWin.modeshell_probe )
    return ;
  /* 現在の状態を見る。*/
  mode_status =
    ( ( skkinput_GetModelineNumber( node ) ) |
      ( w->offthespotWin.buffer.jisyo_dirty << 3 ) |
      ( w->offthespotWin.buffer.overthespot_like_input << 4 ) ) ;
  if( w->offthespotWin.prevModeStatus != mode_status ){
    /* 書き直しのためにウィンドウを消去する。*/
    XClearWindow( XtDisplay( gw ), win ) ;
    w->offthespotWin.prevModeStatus = mode_status ;
  }
  /* モードラインを表示する。差分表示に直に対応する予定ではある。*/
  fullDrawModeLine
    ( XtDisplay( gw ), win,
      w->offthespotWin.fontset, w->offthespotWin.gc,
      node, 0, w->offthespotWin.font_ascent,
      w->offthespotWin.buffer.jisyo_dirty,
      w->offthespotWin.buffer.overthespot_like_input ) ;
  return ;
}

/*
 * modeshell window にモードを表示をする関数。
 */
static void Modeshell_Redisplay
( Widget gw, Window win )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )gw ;
  struct SKKInputNode *node = w->offthespotWin.buffer.topbuffer ;

  /* モードウィンドウが存在していなかったら書かない。*/
  if( !w->offthespotWin.modeshell_probe )
    return ;
  /* 書き直しのためにウィンドウを消去する。*/
  XClearWindow( XtDisplay( gw ), win ) ;
  /* モードラインを表示する。差分表示に直に対応する予定ではある。*/
  fullDrawModeLine
    ( XtDisplay( gw ), win,
      w->offthespotWin.fontset, w->offthespotWin.gc,
      node, 0, w->offthespotWin.font_ascent,
      w->offthespotWin.buffer.jisyo_dirty,
      w->offthespotWin.buffer.overthespot_like_input ) ;
  w->offthespotWin.prevModeStatus =
    ( ( skkinput_GetModelineNumber( node ) ) |
      ( w->offthespotWin.buffer.jisyo_dirty << 3 ) |
      ( w->offthespotWin.buffer.overthespot_like_input << 4 ) ) ;
  return ;
}

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

static void OFFW_wmMessageCloseCallback
( Widget gw, caddr_t client, caddr_t caller )
{
  OffthespotWinWidget w = ( OffthespotWinWidget )client ;
  
  force_keyboard_quit( ( Widget )w, &( w->offthespotWin.buffer ) ) ;
  return ;
}

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

static void
OffWin_fixcallback (
	register Widget		gw,
	register XtPointer	client,
	register XtPointer	caller)
{
	XtCallCallbacks (gw, XtNtextNotify, caller) ;
	return ;
}

