/* # skkinput (Simple Kana-Kanji Input)
 * OverWin.c --- Making OverTheSpotWinWidget.
 * 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 <limits.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>

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

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

#define offset(field) XtOffsetOf (OverthespotWinRec, overthespotWin.field)
#define goffset(field) XtOffsetOf (WidgetRec, core.field)

static XtResource OTSW_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},
  /* Overthespot で利用する漢字フォント及びローマ字フォント。*/
  { 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 (OverthespotWinRec, overthespotWin.buffer.egg_like_newline),
    XtRImmediate, (XtPointer) FALSE},
  /* chat-adapter-mode か否か。*/
  { XtNchatAdapter, XtCChatAdapter, XtRImmediate, sizeof (Boolean),
    XtOffsetOf (OverthespotWinRec, overthespotWin.buffer.chat_adapter),
    XtRImmediate, (XtPointer) FALSE},
  { XtNjisyoDirty, XtCJisyoDirty, XtRImmediate, sizeof (Boolean),
    XtOffsetOf (OverthespotWinRec, overthespotWin.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 },
  {	XtNinput,	XtCInput,	XtRBoolean,		sizeof (Boolean),
    offset (m_fInputFocus),	XtRImmediate,  (XtPointer)TRUE },
  /* カーソルを常に南側に表示する…。*/
  { 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 (OverthespotWinRec, overthespotWin.buffer.toggleShiftMode),
    XtRImmediate,  (XtPointer)FALSE },
  { XtNcontrolHaTugiDeYukou, XtCControlHaTugiDeYukou, XtRBoolean,
    sizeof (Boolean), 
    XtOffsetOf (OverthespotWinRec, overthespotWin.buffer.toggleControlMode),
    XtRImmediate,  (XtPointer)FALSE },
  { XtNmodeshell_geometry, XtCModeShell_Geometry, XtRString,
    sizeof (String),
    XtOffsetOf (OverthespotWinRec, overthespotWin.modeshell_geometry),
    XtRImmediate, (XtPointer)DEFAULT_MODELINE_GEOMETRY},
} ;

#undef offset
#undef goffset

/*
 * プロトタイプ宣言。
 */
/*
 * このウィジェットを構成している基本要素となる関数たち。
 */
static void OTSW_Initialize
 (Widget greq, Widget gnew, ArgList args, Cardinal *num_args) ;
static void OTSW_Realize
 (Widget gw, XtValueMask *valueMask, XSetWindowAttributes *attrs) ;
static void OTSW_Redisplay
 (Widget gw, XEvent *event, Region region) ;
static void OTSW_Destroy (Widget gw) ;
static Boolean OTSW_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 OTSW_CreateAllGCs (Widget gw) ;
static void OTSW_CreateMinibufferGCs (Widget gw) ;
static void OTSW_ReleaseAllGCs (Widget gw) ;
static void OTSW_ReleaseMinibufferGCs (Widget gw) ;

static int OTSW_ChangeAttributes
 (Widget gw, unsigned long valuemask, struct ConvAttrs *values) ;
static void OTSW_resetupModeWindow (Widget gw) ;
static void OTSW_ReconfigureColor
 (Widget gw, unsigned long valuemask) ;

static void OTSW_ConfigureMinibuffer (Widget gw) ;
static int OTSW_ConfigureSubWindowMinibuffer (Widget gw, int flag) ;

static void OTSW_RedrawScreen (Widget gw) ;

static void OTSW_ConfigureWindowsScreenIsSmall
 (Widget gw,                  int endx, int endy,
  struct myChar *linetop,     int linetop_pos,
  struct myChar *midline_top, int midline_pos) ;
static int OTSW_ReconfigureFocusPosition
 (Widget gw) ;

static int focusCheck (Widget gw) ;

static void Minibuffer_Redisplay (Widget gw, Window win) ;

/*
 * callbacks
 */
static void Topline_Redisplay
 (Widget gw, Window win) ;
static void Midline_Redisplay
 (Widget gw, Window win) ;
static void Botline_Redisplay
 (Widget gw, Window win) ;
static void Modeshell_Display
 (Widget gw, Window win) ;
static void Modeshell_Redisplay
 (Widget gw, Window win) ;

static void Minibuffer_RedisplayCallback
 (Widget gw, caddr_t client, caddr_t caller) ;
static void OTSW_wmMessageCloseCallback
 (Widget gw, caddr_t client, caddr_t caller) ;
static void OTSW_wmShellDestroyCallback
 (Widget gw, caddr_t client, caddr_t caller) ;
static void Canvas_DestroyCallback
 (Widget gw, caddr_t client, caddr_t caller) ;
static void		OverWin_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 overthespotWinActionsTable [] = {
  { "KeyDownEventHandler",	   KeyDownEventHandler },
  { "FocusInEventHandler",	   FocusEventHandler },
  { "FocusOutEventHandler",	   FocusEventHandler },
};

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

OverthespotWinClassRec overthespotWinClassRec = {
    { /* core fields */
    /* superclass		*/	&widgetClassRec,
    /* class_name		*/	"Overthespot",
    /* size			*/	sizeof (OverthespotWinRec),
    /* class_initialize		*/	NULL,
    /* class_part_initialize	*/	NULL,
    /* class_inited		*/	FALSE,
    /* initialize		*/	OTSW_Initialize,
    /* initialize_hook		*/	NULL,
    /* realize			*/	OTSW_Realize,
    /* actions			*/	overthespotWinActionsTable,
    /* num_actions		*/	XtNumber (overthespotWinActionsTable),
    /* resources		*/	OTSW_resources,
    /* num_resources		*/	XtNumber (OTSW_resources),
    /* xrm_class		*/	NULLQUARK,
    /* compress_motion		*/	TRUE,
    /* compress_exposure	*/	TRUE,
    /* compress_enterleave	*/	TRUE,
    /* visible_interest		*/	FALSE,
    /* destroy			*/	OTSW_Destroy,
    /* resize			*/	NULL,
    /* expose			*/	OTSW_Redisplay,
    /* set_values		*/	OTSW_SetValues,
    /* set_values_hook		*/	NULL,
    /* set_values_almost	*/	XtInheritSetValuesAlmost,
    /* get_values_hook		*/	NULL,
    /* accept_focus		*/	NULL,
    /* version			*/	XtVersion,
    /* callback_private		*/	NULL,
    /* tm_table			*/	defaultOverthespotWinTranslations,
    /* query_geometry		*/	XtInheritQueryGeometry,
    }
};

WidgetClass overthespotWinWidgetClass =
 (WidgetClass)&overthespotWinClassRec ;

static void OTSW_InitializeHistory (Widget gw)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)gw ;

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

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

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

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

  /* フォントセットを初期化する。*/
  for (i = 0 ; i < NUMBER_OF_CHARSET ; i ++){
    w->overthespotWin.fontset[ i ] = NULL ;
    w->overthespotWin.minibuf_fontset[ i ] = NULL ;
  }
  w->overthespotWin.gc = w->overthespotWin.rgc = NULL ;
  w->overthespotWin.minibuf_gc = w->overthespotWin.minibuf_rgc = NULL ;

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

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

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

  /* Over-the-spot Window として機能させるために必要な変数の初期化。*/
  w->overthespotWin.focus_window = None ;
  w->overthespotWin.input_focus_window = None ;
  w->overthespotWin.spot_x = w->overthespotWin.spot_y = 0 ;
  w->overthespotWin.focus_offset_x =
    w->overthespotWin.focus_offset_y = 0 ;
  w->overthespotWin.client_x =
    w->overthespotWin.client_y = 0 ;
  w->overthespotWin.client_area.x = 
    w->overthespotWin.client_area.y = 0 ;
  w->overthespotWin.client_area.height = 
    w->overthespotWin.client_area.width = 0 ;
  w->overthespotWin.status_area.x = 
    w->overthespotWin.status_area.y = 0 ;
  w->overthespotWin.status_area.height = 
    w->overthespotWin.status_area.width = 0 ;

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

  w->overthespotWin.attribute_mask = 0L ;

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

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

  w->overthespotWin.modeshell_border_width = 2 ;
  w->overthespotWin.modeshell_width =
    w->overthespotWin.modeshell_height = 1 ;

  w->overthespotWin.topline_win =
    w->overthespotWin.midline_win =
    w->overthespotWin.botline_win =
    w->overthespotWin.modeshell_win = 
    w->overthespotWin.minibuffer_win = None ;
  return ;
}

static void OTSW_ReleaseAllGCs (Widget gw)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
  if (w->overthespotWin.gc != NULL)
    XFreeGC (XtDisplay (gw), w->overthespotWin.gc) ;
  if (w->overthespotWin.rgc != NULL)
    XFreeGC (XtDisplay (gw), w->overthespotWin.rgc) ;
  w->overthespotWin.gc = w->overthespotWin.rgc = NULL ;
  return ;
}

static void OTSW_ReleaseMinibufferGCs (Widget gw)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
  if (w->overthespotWin.minibuf_gc != NULL)
    XFreeGC (XtDisplay (gw), w->overthespotWin.minibuf_gc) ;
  if (w->overthespotWin.minibuf_rgc != NULL)
    XFreeGC (XtDisplay (gw), w->overthespotWin.minibuf_rgc) ;
  w->overthespotWin.minibuf_gc = w->overthespotWin.minibuf_rgc = NULL ;
  return ;
}

static void OTSW_FreeFontSet (Widget gw)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
  int i ;

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

static void OTSW_CreateAllGCs (Widget gw)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
  Window drawable = w->overthespotWin.focus_window ;
  XGCValues values ;

  values.foreground = w->overthespotWin.oforeground ;
  values.background = w->overthespotWin.obackground ;
  w->overthespotWin.gc = XCreateGC
     (XtDisplay (gw), drawable, GCForeground | GCBackground, &values) ;
  values.foreground = w->overthespotWin.obackground ;
  values.background = w->overthespotWin.oforeground ;
  w->overthespotWin.rgc = XCreateGC
     (XtDisplay (gw), drawable, GCForeground | GCBackground, &values) ;
  return ;
}

static void OTSW_CreateMinibufferGCs (Widget gw)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
  XGCValues values ;

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

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

static Window OTSW_CreateModeShellWin
 (Widget gw, Window focus_window, int *probe, int border_width)
{
  OverthespotWinWidget	w	=  (OverthespotWinWidget)gw ;
  Window		win ;
  XSetWindowAttributes attr;

  if (border_width <= 0){
    win = XCreateSimpleWindow
       (XtDisplay (gw), focus_window, 0, 0, 1, 1, 0,
	w->overthespotWin.obackground,
	w->overthespotWin.obackground) ;
  } else {
    win = XCreateSimpleWindow
       (XtDisplay (gw), focus_window, 0, 0, 1, 1, border_width,
	w->overthespotWin.oforeground,
	w->overthespotWin.obackground) ;
  }
  attr.override_redirect = True;
  XChangeWindowAttributes (XtDisplay (gw), win, CWOverrideRedirect, &attr);
  /* 作りはしたものの必要になるまでは、map しない。*/
  *probe = False ;
  return win ;
}

static Window OTSW_CreateSubCanvas
 (Widget gw, Window focus_window, int *probe, int border_width)
{
  OverthespotWinWidget	w	=  (OverthespotWinWidget)gw ;
  Window		win ;
  XSetWindowAttributes	xswa ;

  if (border_width <= 0){
    win = XCreateSimpleWindow
       (XtDisplay (gw), focus_window, 0, 0, 1, 1, 0,
	w->overthespotWin.obackground,
	w->overthespotWin.obackground) ;
  } else {
    win = XCreateSimpleWindow
       (XtDisplay (gw), focus_window, 0, 0, 1, 1, border_width,
	w->overthespotWin.oforeground,
	w->overthespotWin.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) ;

  /* SaveUnder にしないと modeshell の移動によって ExposureEvent が親に飛んでしまう。*/
  xswa.save_under = True ;
  XChangeWindowAttributes (XtDisplay(gw), win, CWSaveUnder, &xswa) ;

  /* avoid Unmap on Qt by setting over-ride-redirect */
  xswa.override_redirect = True ;
  XChangeWindowAttributes (XtDisplay(gw), win, CWOverrideRedirect, &xswa) ;

  /* 作りはしたものの必要になるまでは、map しない。*/
  *probe = False ;
  return win ;
}

static int OTSW_ParseModeShellGeometry(Widget gw)
{
  OverthespotWinWidget ow = (OverthespotWinWidget)gw;
  int x, y;
  unsigned int w, h;
  int r;

  x = y = 0;
  w = h = 0;
  r = XParseGeometry(ow->overthespotWin.modeshell_geometry, &x, &y, &w, &h);
  if (r == 0) {
    /* not specified, or invalid geometry */
    return 0;
  }
  if ((r & XValue) == XValue) {
    ow->overthespotWin.modeshell_x = x;
  }
  if ((r & YValue) == YValue) {
    ow->overthespotWin.modeshell_y = y;
  }
  /* not recommended? */
  if ((r & WidthValue) == WidthValue) {
    ow->overthespotWin.modeshell_width = w;
  }
  if ((r & HeightValue) == HeightValue) {
    ow->overthespotWin.modeshell_height = h;
  }

  if ((r & XNegative) == XNegative) {
    ow->overthespotWin.modeshell_x = 
      DisplayWidth (XtDisplay (gw), DefaultScreen (XtDisplay (gw))) 
      - ow->overthespotWin.modeshell_width - 10;
  }
  if ((r & YNegative) == YNegative) {
    ow->overthespotWin.modeshell_y = 
      DisplayHeight (XtDisplay (gw), DefaultScreen (XtDisplay (gw))) 
      - ow->overthespotWin.modeshell_height - 10;
  }
  return r;
}

/*
 * [かな--]のモードシェルを表示するウィンドウを作成する関数。
 *---
 * 状況に応じて次のようなことをしています。
 *  1. ステータスエリアの指定がある場合 ..... 
 *         モードシェルはステータスエリアに固定して置きます。 
 *  2. ステータスエリアが無い場合 .....
 *         モードシェルはフォーカスウィンドウの中を移動します。
 */
static void OTSW_CreateModeShell (Widget gw)
{
	OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
	Window parentwin ;
	int border_width ;

	if ((w->overthespotWin.attribute_mask & CAStatusArea) &&
		w->overthespotWin.client_window != w->overthespotWin.focus_window){
		/* この場合には、固定モードシェルにする。*/
		parentwin    = w->overthespotWin.client_window ;
		border_width = 0 ;
		w->overthespotWin.fixed_modeshell = True ;
	} else {
		parentwin    = w->overthespotWin.focus_window ;
		border_width = w->overthespotWin.modeshell_border_width ;
		w->overthespotWin.fixed_modeshell = False ;
	}
	/* モードシェルを作成する。*/
	if (OTSW_ParseModeShellGeometry(gw)) {
	    w->overthespotWin.modeshell_win = OTSW_CreateModeShellWin
		(gw, RootWindowOfScreen (XtScreen(gw)), &w->overthespotWin.modeshell_probe, border_width) ;
	} else {
	    w->overthespotWin.modeshell_win = OTSW_CreateSubCanvas
		(gw, parentwin, &w->overthespotWin.modeshell_probe, border_width) ;
	}
	/* 大きさ情報の初期化。resize は一回は通って欲しいものですから。*/
	w->overthespotWin.modeshell_width  = 1 ;
	w->overthespotWin.modeshell_height = 1 ;
	return ;
}

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

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

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

static void
OTSW_CreateMinibuffer (
	register Widget		gw)
{
	register OverthespotWinWidget w =  (OverthespotWinWidget)gw ;

	if ((w->overthespotWin.attribute_mask & CAStatusArea) &&
		w->overthespotWin.client_window != w->overthespotWin.focus_window){
		/* どういう経緯でかこっちは、クライアントに貼り付く。*/
		w->overthespotWin.minibuffer_win = OTSW_CreateSubCanvas
			(gw, w->overthespotWin.client_window,
			 &w->overthespotWin.minibuffer_probe, 0) ;
		if (OTSW_ConfigureSubWindowMinibuffer (gw, False)){
			/* ウィジェットは利用しないので、NULL を入れておく。*/
			w->overthespotWin.minibuffer_popup = 
				w->overthespotWin.minibuffer_canvas = NULL ;
			return ;
		}
		/* 変換クライアントに貼り付くタイプのミニバッファではとても大きさ
		 * が足りないので、別窓に開くタイプにする。*/
		XDestroyWindow (XtDisplay (gw), w->overthespotWin.minibuffer_win) ;
	}
	w->overthespotWin.minibuffer_win = None ;
	w->overthespotWin.minibuffer_ofstx = 0 ;
	OTSW_RealizeMinibuffer (gw) ;

	if (w->overthespotWin.m_fInputFocus) {
		XtSetKeyboardFocus (w->overthespotWin.minibuffer_popup, gw) ;
		XtSetKeyboardFocus (w->overthespotWin.minibuffer_canvas, gw) ;
	}
	return ;
}

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

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

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

	if (w->overthespotWin.focus_window == None){
		w->overthespotWin.focus_window = w->overthespotWin.client_window ;
		if (! (w->overthespotWin.attribute_mask & CAClientArea))
			XGetRectangleOfWindow
				(XtDisplay (gw), w->overthespotWin.focus_window, 
				 &w->overthespotWin.client_area) ;
		OTSW_ReconfigureFocusPosition (gw) ;
	}
	OTSW_CreateAllGCs (gw) ;
	
	/* Minibuffer を作成する。*/
	OTSW_CreateMinibuffer (gw) ;
	OTSW_CreateMinibufferGCs (gw) ;

#if 0
	printf ("Client = %ld, Focus = %ld\n",
			w->overthespotWin.client_window,
			w->overthespotWin.focus_window) ;
#endif
	/* modeshell 表示のためのウィジェットを作成する。*/
	OTSW_CreateModeShell (gw) ;

	/* 本文描画用のキャンバスは3つ必要になる。*/
	w->overthespotWin.topline_win = OTSW_CreateSubCanvas
		(gw, w->overthespotWin.focus_window, 
		 &w->overthespotWin.topline_probe, 0) ;
	w->overthespotWin.midline_win = OTSW_CreateSubCanvas
		(gw, w->overthespotWin.focus_window, 
		 &w->overthespotWin.midline_probe, 0) ;
	w->overthespotWin.botline_win = OTSW_CreateSubCanvas
		(gw, w->overthespotWin.focus_window, 
		 &w->overthespotWin.botline_probe, 0) ;
	
	/*
	 * この位置ならモードシェルを作成しても問題ない。
	 */
	OTSW_resetupModeWindow (gw) ;
	OTSW_ReconfigureColor (gw, CAForegroundPixel | CABackgroundPixel | CAColormap) ;
#if 0
	XSync (XtDisplay (gw), False) ;
#endif
	w->overthespotWin.is_focus = focusCheck (gw) ;
	return ;
}

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

  remove_allmyeventhandler
     (XtDisplay (gw), w->overthespotWin.modeshell_win) ;
  remove_allmyeventhandler
     (XtDisplay (gw), w->overthespotWin.topline_win) ;
  remove_allmyeventhandler
     (XtDisplay (gw), w->overthespotWin.midline_win) ;
  remove_allmyeventhandler
     (XtDisplay (gw), w->overthespotWin.botline_win) ;
  if (w->overthespotWin.minibuffer_win != None){
    remove_allmyeventhandler
       (XtDisplay (gw), w->overthespotWin.minibuffer_win) ;
  } else {
    XSafeSelectInput
       (XtDisplay (gw), XtWindow (w->overthespotWin.minibuffer_popup),
	NoEventMask) ;
    XSafeSelectInput
       (XtDisplay (gw), XtWindow (w->overthespotWin.minibuffer_canvas),
	NoEventMask) ;
  }
  XSafeSelectInput (XtDisplay (gw), XtWindow (gw), NoEventMask) ;
  /* Event Queue をフラッシュしておく。*/
  XSafeFlush (XtDisplay (gw)) ;
  return ;
}

/*
 * SIW に XtDestroyWidget をかけた時に呼び出される関数。
 *-----
 * SIW の終了処理一揃えが入っている。GC を解放してから、malloc してい
 * たメモリを解放している。
 */
static void OTSW_Destroy (Widget gw)
{
	OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
	struct SKKInputNode *node, *pNode ;
	/*
	 * XFreeFont (XtDisplay (gw), w->overthespotWin.fs_kanji) ;
	 * XFreeFont (XtDisplay (gw), w->overthespotWin.fs_roman) ;
	 * どうやら、Widget 毎に確保しているわけじゃないみたいなので、ここで
	 * 解放するとはまるみたいだ。
	 */
	/* Destroy した以上、以下のウィンドウのイベントは全部無視する。*/
	OTSW_IgnoreAllWindowEvent (gw) ;
	OTSW_ReleaseAllGCs (gw) ;
	OTSW_ReleaseMinibufferGCs (gw) ;
	OTSW_FreeFontSet (gw) ;
	
	if (w->overthespotWin.modeshell_win != None)
		XDestroyWindow (XtDisplay (gw), w->overthespotWin.modeshell_win) ;
	if (w->overthespotWin.topline_win != None)
		XDestroyWindow (XtDisplay (gw), w->overthespotWin.topline_win) ;
	if (w->overthespotWin.midline_win != None)
		XDestroyWindow (XtDisplay (gw), w->overthespotWin.midline_win) ;
	if (w->overthespotWin.botline_win != None)
		XDestroyWindow (XtDisplay (gw), w->overthespotWin.botline_win) ;
	if (w->overthespotWin.minibuffer_win != None)
		XDestroyWindow (XtDisplay (gw), w->overthespotWin.minibuffer_win) ;
    
	/*
	 * ヒストリを親へと返す。
	 */
	if (w->overthespotWin.historyAttribute != NULL){
		/* ヒストリについて親に返します。*/
		w->overthespotWin.historyAttribute->history_start =
			w->overthespotWin.buffer.hist_start ;
		w->overthespotWin.historyAttribute->history_end =
			w->overthespotWin.buffer.hist_end ;
		/* その場変換モードの状況について親へと返す。*/
		w->overthespotWin.historyAttribute->overthespot_like_input =
			w->overthespotWin.buffer.overthespot_like_input ;
		/* まあ…その仮名モードの状況を親へと返します。*/
		if (w->overthespotWin.buffer.topbuffer != NULL){
			w->overthespotWin.historyAttribute->j_mode =
				w->overthespotWin.buffer.topbuffer->j_mode ;
			w->overthespotWin.historyAttribute->j_zenkaku =
				w->overthespotWin.buffer.topbuffer->j_zenkaku ;
			w->overthespotWin.historyAttribute->j_katakana_mode =
				w->overthespotWin.buffer.topbuffer->j_katakana_mode ;
		}
	}
	/*
	 * バッファを全て解放しておく。
	 */
	node =  (w->overthespotWin.buffer).lastbuffer ;
	while (node != NULL){
		pNode = node->parentbuffer ;
		free_Minibuffer (gw, & (w->overthespotWin.buffer), node) ;
		node  = pNode ;
	}
	XtCallCallbacks (gw, XtNendNotify, w->overthespotWin.historyAttribute) ;
	w->overthespotWin.historyAttribute = NULL ;
	return ;
}

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

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

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

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

  /* Minibuffer Window が存在しなければ…存在しないことは無いけど、ク
   * ライアントに貼り付くタイプのウィンドウであればリサイズはしない。*/
  if (w->overthespotWin.minibuffer_win != None)
    return ;

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

/*
 * foreground color, background color を変更してという要求が来た場合に 
 * modeshell などの背景色を変更して GC の foreground color を変更する
 * 関数。
 */
static void OTSW_ReconfigureColor (Widget gw, unsigned long valuemask)
{
	OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
	unsigned long mask ;
	XSetWindowAttributes xswa ;

	mask = 0L ;
	if (valuemask & CABackgroundPixel){
		mask	|= CWBackPixel ;
		xswa.background_pixel = w->overthespotWin.obackground ;
	}
	if (valuemask & CAForegroundPixel) {
		mask	|= CWBorderPixel ;
		xswa.border_pixel     = w->overthespotWin.oforeground ;
	}
	if (valuemask & CAColormap){
		mask |= CWColormap ;
		xswa.colormap = w->overthespotWin.colormap ;
	}
	if (mask){
		XChangeWindowAttributes
			(XtDisplay (gw), w->overthespotWin.modeshell_win, 
			 mask, &xswa) ;
		XChangeWindowAttributes
			(XtDisplay (gw), w->overthespotWin.topline_win, 
			 mask, &xswa) ;
		XChangeWindowAttributes
			(XtDisplay (gw), w->overthespotWin.midline_win, 
			 mask, &xswa) ;
		XChangeWindowAttributes
			(XtDisplay (gw), w->overthespotWin.botline_win, 
			 mask, &xswa) ;
		if (w->overthespotWin.minibuffer_win != None){
			XChangeWindowAttributes
				(XtDisplay (gw), w->overthespotWin.minibuffer_win, 
				 mask, &xswa) ;
		}
	}
	if (! (valuemask & (CAForegroundPixel | CABackgroundPixel)))
		return ;

	/* GC の foreground, background を変更する。*/
	if (XtIsRealized (gw)){
		OTSW_ReleaseAllGCs (gw) ;
		OTSW_CreateAllGCs (gw) ;
	}
	return ;
}

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

  /* 辞書が修正されていたら、書き直しを実行する。*/
  if (curw->overthespotWin.buffer.jisyo_dirty !=
      reqw->overthespotWin.buffer.jisyo_dirty){
    neww->overthespotWin.buffer.jisyo_dirty =
      reqw->overthespotWin.buffer.jisyo_dirty ;
    /* 窓が起きていなければ実行しないぞ、と。*/
    if (neww->overthespotWin.modeshell_probe){
      Modeshell_Redisplay (new, neww->overthespotWin.modeshell_win) ;
    }
    return False ;
  }
  /* 変換属性の修正要求が来た場合と見付けたり。*/
  if (reqw->overthespotWin.camsg != NULL){
    int ret ;
    camsg = reqw->overthespotWin.camsg ;
    reqw->overthespotWin.camsg = neww->overthespotWin.camsg = 
      curw->overthespotWin.camsg = NULL ;

    ret = OTSW_ChangeAttributes
       (new, camsg->mask, &camsg->value) ;
    /* 変更の影響があって、しかも realize していた場合には…修正する。*/
    if (XtIsRealized (new) && ret)
      OTSW_ReconfigureWindows (new) ;
    return ret ;
  }
  /* ミニバッファを消去したいという要望を受けた時の処理を行う。*/
  if (reqw->overthespotWin.clearMinibuffer){
    if (curw->overthespotWin.minibuffer_probe){
      if (curw->overthespotWin.minibuffer_win != None){
	XUnmapWindow
	   (XtDisplay (curw), curw->overthespotWin.minibuffer_win) ;
      } else {
	XtPopdown (curw->overthespotWin.minibuffer_popup) ;
      }
      curw->overthespotWin.minibuffer_probe =
	reqw->overthespotWin.minibuffer_probe =
	neww->overthespotWin.minibuffer_probe = False ;
    }
    reqw->overthespotWin.clearMinibuffer =
      neww->overthespotWin.clearMinibuffer = 
      curw->overthespotWin.clearMinibuffer = False ;
    return FALSE ;
  }
  if (reqw->overthespotWin.conversion_set_focus){
    reqw->overthespotWin.conversion_set_focus = 
      neww->overthespotWin.conversion_set_focus = 
      curw->overthespotWin.conversion_set_focus = False ;
    /* modeshell を復活させる。*/
    if (!neww->overthespotWin.modeshell_probe){
      XMapWindow (XtDisplay (neww), neww->overthespotWin.modeshell_win) ;
      neww->overthespotWin.modeshell_probe = True ;
      OTSW_resetupModeWindow (new);
    }
    /* mini-buffer を表示する。もし必要ならば…であるが。*/
    OTSW_ConfigureMinibuffer (new) ;
    return FALSE ;
  }
  if (reqw->overthespotWin.conversion_unset_focus){
    reqw->overthespotWin.conversion_unset_focus = 
      neww->overthespotWin.conversion_unset_focus = 
      curw->overthespotWin.conversion_unset_focus = False ;
    if (neww->overthespotWin.modeshell_probe){
      XUnmapWindow (XtDisplay (new), neww->overthespotWin.modeshell_win) ;
      neww->overthespotWin.modeshell_probe = False ;
    }
    return FALSE ;
  }
  return (FALSE) ;
}

/*
 *
 */
static int OTSW_ReconfigureFocusPosition
 (Widget gw)
{
	OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
	int			x, y, ofx, ofy ;
	Window		dummy ;
	int			ret = False ;

	/* ルートウィンドウ内でのフォーカスウィンドウの絶対位置を算出 *
	 * する。*/
	XTranslateCoordinates
		(XtDisplay (gw), w->overthespotWin.client_window,
		 RootWindowOfScreen (XtScreen (gw)),
		 0, 0, &x, &y, &dummy) ;
	if (w->overthespotWin.focus_window != w->overthespotWin.client_window){
		XTranslateCoordinates
			(XtDisplay (gw), w->overthespotWin.focus_window,
			 w->overthespotWin.client_window, 
			 0, 0, &ofx, &ofy, &dummy) ;
	} else {
		ofx = ofy = 0 ;
	}
	if (w->overthespotWin.client_x != x || w->overthespotWin.client_y != y){
		w->overthespotWin.client_x = x ;
		w->overthespotWin.client_y = y ;
		ret = True ;
	}
	if (w->overthespotWin.focus_offset_x != ofx ||
		w->overthespotWin.focus_offset_y != ofy){
		w->overthespotWin.focus_offset_x = ofx ;
		w->overthespotWin.focus_offset_y = ofy ;
		ret = True ;
	}
	return ret ;
}

/*
 */
static void OTSW_ChangeFocusWindow (
	register Widget	gw,
	register Window	focus_win)
{
	register Display*	pDisplay	= XtDisplay (gw) ;
	OverthespotWinWidget w =  (OverthespotWinWidget)gw ;

	XReparentWindow (pDisplay, w->overthespotWin.topline_win, focus_win, 0, 0) ;
	XReparentWindow (pDisplay, w->overthespotWin.midline_win, focus_win, 0, 0) ;
	XReparentWindow (pDisplay, w->overthespotWin.botline_win, focus_win, 0, 0) ;
	
	/* focus window にはりついていたウィンドウを全て破棄する。*/
	if (!w->overthespotWin.fixed_modeshell)
		XReparentWindow (pDisplay, w->overthespotWin.modeshell_win, focus_win, 0, 0) ;

	w->overthespotWin.focus_window = focus_win ;
	OTSW_ReleaseAllGCs (gw) ;
	OTSW_CreateAllGCs (gw) ;
	return ;
}

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

	if (valuemask & CAFocusWindow){
#if defined (DEBUG)
		fprintf (stderr, "(OTSW)Focus window (%ld)\n", values->focus_window) ;
#endif
		/* フォーカス先の窓って実在するの？ とか実はもう少しきっちりと *
		 * 見る必要があると思う。*/
		if (values->focus_window != None){
			/* 一度設定した筈のフォーカスが別物になっていたら、不味いんでは */
			/* ないかい？ という話です。*/
			if (w->overthespotWin.focus_window != None &&
				w->overthespotWin.focus_window != values->focus_window){
				/* フォーカスだけを修正する。*/
				OTSW_ChangeFocusWindow
					(gw, values->focus_window) ;
				/* 以前のクライアントエリアに対する情報は今回においては正しく
				 * なくなるので、破棄する。*/
				w->overthespotWin.attribute_mask &= ~ (CAClientArea) ;
			} else {
				w->overthespotWin.focus_window = values->focus_window ;
			}
			/* 変換クライアントの領域に対する情報が無かったら自前で用意して *
			 * おく。これが正しいかどうかなんて保証はないのだけど、変換クラ *
			 * イアントがくれないんだもん仕方無いよね 。*/
			if (!((w->overthespotWin.attribute_mask) & CAClientArea)){
				XGetRectangleOfWindow
					(XtDisplay (gw), w->overthespotWin.focus_window,
					 &w->overthespotWin.client_area) ;
			}
			ret = True ;
		}
	}
	if (valuemask & CAStatusArea){
		/* 座標の修正があった、もしくは表示領域が修正されている場合。*/
		if (values->status_area.x != w->overthespotWin.status_area.x ||
			values->status_area.y != w->overthespotWin.status_area.y ||
			values->status_area.width  != w->overthespotWin.status_area.width || 
			values->status_area.height != w->overthespotWin.status_area.height){
			w->overthespotWin.status_area.x = values->status_area.x ;
			w->overthespotWin.status_area.y = values->status_area.y ;
			w->overthespotWin.status_area.width  = values->status_area.width ;
			w->overthespotWin.status_area.height = values->status_area.height ;
			w->overthespotWin.attribute_mask |= CAStatusArea ;
#ifdef DEBUG
			printf ("Status Area: (x,y,w,h) = (%d,%d,%d,%d)\n",
					values->status_area.x, values->status_area.y,
					values->status_area.width, values->status_area.height) ;
#endif
			ret = True ;
		}
	}
	rec_col = False ;
	/* カラーマップの変更要求が来ていたら、それを受ける。*/
	if ((valuemask & CAColormap) &&
		w->overthespotWin.colormap != values->colormap){
		w->overthespotWin.colormap = values->colormap ;
#if defined(DEBUG)
		fprintf (stderr, "(OTSW)Change colormap.\n") ;
#endif
		rec_col = True ;
	}
	/* フォアグラウンドカラー及びバックグラウンドカラーの変更要求が来て *
	 * いたら、それを受ける…。*/
	if ((valuemask & CAForegroundPixel) &&
		w->overthespotWin.oforeground != values->foreground){
#if defined(DEBUG)
		fprintf (stderr, "(OTSW)Change foreground and background colors.\n") ;
#endif
		w->overthespotWin.oforeground = values->foreground ;
		rec_col = True ;
	}
	if ((valuemask & CABackgroundPixel) &&
		w->overthespotWin.obackground != values->background) {
		w->overthespotWin.obackground = values->background ;
		rec_col = True ;
	}
	if (XtIsRealized (gw) && rec_col){
		OTSW_ReconfigureColor (gw, valuemask) ;
		ret = True ;
	}
	/* 変換クライアントの表示領域の修正通知が来た場合の処理。*/
	if (valuemask & CAClientArea){
		/* 座標の修正があった、もしくは表示領域が修正されている場合。*/
		if (values->client_area.x != w->overthespotWin.client_area.x ||
			values->client_area.y != w->overthespotWin.client_area.y ||
			values->client_area.width != w->overthespotWin.client_area.width || 
			values->client_area.height != w->overthespotWin.client_area.height){
			/* 変換クライアントの表示領域の変更を覚えておく。*/
			w->overthespotWin.client_area    = values->client_area ;
#ifdef DEBUG
			fprintf	(stderr, "(OTSW)Client pos:(%d,%d), size:%d x %d.\n",
					 w->overthespotWin.client_area.x,
					 w->overthespotWin.client_area.y,
					 w->overthespotWin.client_area.width,
					 w->overthespotWin.client_area.height) ;
#endif
			w->overthespotWin.attribute_mask |= CAClientArea ;
			ret = True ;
		}
	}
	/* 座標を修正せよという要求が来ていた場合の処理を行う。*/
	if (valuemask & CASpotLocation){
		if (w->overthespotWin.focus_window != None){
			int prev_focus ;
#if defined(DEBUG)
			fprintf (stderr, "CASPOT nanode FOCUSWINDOW miru (%ld).\n",
					 w->overthespotWin.focus_window) ;
#endif
			prev_focus = w->overthespotWin.is_focus ;
			w->overthespotWin.is_focus = focusCheck (gw) ;
			if (prev_focus != w->overthespotWin.is_focus){
				ret = True ;
			}
			if (OTSW_ReconfigureFocusPosition (gw))
				ret = True ;
		}
		if (values->spot_x != w->overthespotWin.spot_x ||
			values->spot_y != w->overthespotWin.spot_y){
#ifdef DEBUG
			fprintf (stderr, "Get Basho Shitei meirei.\n") ;
#endif
			/* カーソル位置を修正するさ。*/
			w->overthespotWin.spot_x = values->spot_x ;
			w->overthespotWin.spot_y = values->spot_y ;
			ret = True ;
		}
	}
	/* フォント情報の修正があった場合の処理。*/
	if (valuemask & CAFonts){
		/* フォント情報を更新する。この時クライアント側のフォントの情報に
		 * 全て合わせるものとする。例え、クライアントが補助漢字フォントを
		 * 指定してくれなくてデフォルトのフォントを使うことになり、そのフォ
		 * ントの高さが合わなくても…。(見栄えのため) */
		if (fontMgr_GetFontSetInfo
			(values->fontset,
			 &w->overthespotWin.font_height,
			 &w->overthespotWin.font_ascent)){
			/* フォントセットをコピーする。*/
			fontMgr_CopyFontSet
				(XtDisplay (gw), w->overthespotWin.fontset, values->fontset) ;
			/* ミニバッファとモードシェルの大きさを修正する。*/
			if (XtIsRealized (gw))
				OTSW_ResizeMinibufferAndModeshell (gw) ;
			ret = True ;
		}
	}
	/* フォントの高さに関する制約が送られて来ている場合には…。*/
	if (valuemask & CALineSpacing){
		if (values->linespacing > 0){
			w->overthespotWin.font_height = values->linespacing ;
			ret = True ;
		}
	}
	if (( (valuemask & CAFonts) ||  (valuemask & CAStatusArea)) &&
		w->overthespotWin.minibuffer_win != None){
		OTSW_ConfigureSubWindowMinibuffer (gw, True) ;
	}
	return ret ;
}

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

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

/*
 * 現在マウスがフォーカスされているかどうかをチェックするための関数。
 *-----
 * 現在知られているバグとして、フォーカスの移動を非常に上手くすると、
 * Pointer が存在していることを見逃してしまうことがある…。こんなん分
 * かるかい！
 */
static int focusCheck (Widget gw)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)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)
    return False ;
  if (mouse_focus == PointerRoot)
    return True ;

  if (w->overthespotWin.input_focus_window != None){
    if (mouse_focus == w->overthespotWin.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->overthespotWin.focus_window == childwin){
      if (w->overthespotWin.input_focus_window == None){
	w->overthespotWin.input_focus_window = mouse_focus ;
      }
      return True ;
    }
    if (w->overthespotWin.focus_window == mouse_focus)
      return True ;
    /* ミニバッファウィンドウが開いている場合もあり得るよ。*/
    if (w->overthespotWin.minibuffer_probe){
      Window win ;
      if (w->overthespotWin.minibuffer_win != None){
	win = w->overthespotWin.minibuffer_win ;
      } else {
	win = XtWindow (w->overthespotWin.minibuffer_popup) ;
      }
      if (win == childwin || win == mouse_focus)
	return True ;
    }
  }
  return False ;
}

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

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

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

/*
 * 真中の行を描画する関数。
 *------
 * ここは複数行書かなければならないかもしれないので、描画すべき行数を
 * 渡す必要がある。
 */
static int OTSW_FullDrawTopBufferMiddleLines
 (Display *disp, Window win, struct skkinputManagedFont **fontset,
  GC gc, GC rgc, struct myChar *text, int text_pos,
  int font_ascent, int font_height, int width, int line_num,
  int cur_pos, int cur_exist, int is_focus)
{
  int x = 0, y = 0, xdiff ;
  int cursor_flag = False ;
  
  for (; !IS_END_OF_STRING (*text) ; text ++, text_pos ++){
    /* charset の判別とそれによるフォント幅の計算。*/
    xdiff = myCharTextWidth (fontset, text, 1) ;
    /* 画面の右端まで描画したのかどうかを判断する。*/
    if ((x + xdiff) >= width){
      XDrawLine (disp, win, gc, x, y, width, y + font_height) ;
      y += font_height ;
      x = 0 ;
      line_num -- ;
      if (line_num <= 0)
	break ;
    }
    /* カーソルを表示する場所なのかどうかを判定する。*/
    if (text_pos == cur_pos && cur_exist){
      skkinputDrawCursor
	 (disp, win, gc, rgc,
	  x, y + font_ascent, font_ascent, xdiff,
	  font_height, is_focus) ;
      cursor_flag = True ;
    }
    /* 改行コードの場合には…表示位置を修正する必要がある。*/
    if (IS_ASCII_EQUAL (*text, '\n')){
      y += font_height ;
      x  = 0 ;
      line_num -- ;
      if (line_num <= 0)
	break ;
    } else {
      if (cursor_flag){
	if (is_focus){
	  skkwin_jputMyChar
	     (disp, win, fontset, rgc, gc, 
	      x, y + font_ascent, *text, 
	      font_height, font_ascent, True) ;
	} else {
	  skkwin_jputMyChar
	     (disp, win, fontset, gc, rgc, 
	      x, y + font_ascent, *text, 
	      font_height, font_ascent, True) ;
	}
      } else {
	skkwin_jputMyChar
	   (disp, win, fontset, gc, rgc, 
	    x, y + font_ascent, *text, 
	    font_height, font_ascent, False) ;
      }
      x += xdiff ;
    }
    cursor_flag = False ;
  }
  return text_pos ;
}

static void XQueryPopdown (Widget gw, int *probe, Window win)
{
  if (probe){
    XUnmapWindow (XtDisplay (gw), win) ;
    *probe = False ;
  }
  return ;
}

/*
 * うう…無茶苦茶大きくて汚ない関数になった。ちょっと修正する必要があ
 * る。
 */
static void OTSW_CalcSizeOfBufferWindows (Widget gw)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
  int x, y; 			/* 表示位置 */
  int width, height ;		/* 画面サイズ。*/
  struct SKKInputNode *node ;
  struct myChar *text ;
  struct myChar *line_top, *midline_top ;
  int cursor_flag, pos, linetop_pos, line_num, midline_pos = 0 ;
  int xdiff ;			/* 文字幅。*/

  /* まず初期座標をセットしておく。*/
  x = w->overthespotWin.spot_x ;
  y = w->overthespotWin.spot_y ;

  /* 表示領域の大きさというものを計算しておく。*/
  width  = w->overthespotWin.client_area.width + 
    w->overthespotWin.client_area.x ;
  height = w->overthespotWin.client_area.height +
    w->overthespotWin.client_area.y ;

  /* 調べなければならない文字列の先頭にあわせておく。*/
  node = w->overthespotWin.buffer.topbuffer ;
  text = node->textbuffer ;

  if (IS_END_OF_STRING (*text)){
    /* 文字列が一つも入っていなかったら、バッファの中身を表示するため *
     * の窓なんていうのは不要になるのだから、消してしまう。この時に、 *
     * 既に存在していないような窓を消してしまうと怒られてしまうので注 *
     * 意すること */
    XQueryPopdown
       (gw, &w->overthespotWin.topline_probe, 
	w->overthespotWin.topline_win) ;
    XQueryPopdown
       (gw, &w->overthespotWin.midline_probe, 
	w->overthespotWin.midline_win) ;
    XQueryPopdown
       (gw, &w->overthespotWin.botline_probe, 
	w->overthespotWin.botline_win) ;
    w->overthespotWin.canvas_lines = 0 ;
    return ;
  }
  line_top    = text ;
  linetop_pos = 0 ;
  line_num    = 0 ;
  midline_top = NULL ;
  cursor_flag = False ;

  /* ここから調べることになる。*/
  for (pos = 0 ; !IS_END_OF_STRING (*text) ; text ++, pos ++){
    xdiff = myCharTextWidth (w->overthespotWin.fontset, text, 1) ;
    if ((x + xdiff) >= width){
      if ((y + w->overthespotWin.font_height) >= height){
	goto exit_loop ;
      } else {
	y += w->overthespotWin.font_height ;
	x =  w->overthespotWin.client_area.x ;
	line_num ++ ;
      }
      /* 行頭の位置を覚えておく。これはカーソル表示とかのために必要。*/
      line_top    = text ;
      linetop_pos = pos ;
      /* 2行目の行頭位置を覚えておく。*/
      if (midline_top == NULL){
	midline_top = line_top ;
	midline_pos = linetop_pos ;
      }
    }
    /* カーソルを表示する場所なのかどうかを判定する。*/
    if (pos == node->cur_pos &&
	 (( (y + w->overthespotWin.font_height) < height)))
      cursor_flag = True ;
    if (IS_ASCII_EQUAL (*text, '\n')){
      if ((y + w->overthespotWin.font_height) >= height){
	goto exit_loop ;
      } else {
	y += w->overthespotWin.font_height ;
	x =  w->overthespotWin.client_area.x ;
	line_num ++ ;
      }
      /* 行頭の位置を覚えておく。これはカーソル表示とかのために必要。
       */
      line_top    = text + 1 ;
      linetop_pos = pos + 1 ;
      /* 2行目の行頭位置を覚えておく。*/
      if (midline_top == NULL){
	midline_top = line_top ;
	midline_pos = linetop_pos ;
      }
    } else {
      x += xdiff ;
    }
  }
  /* ここまででカーソルが表示されていなかった場合の処理。*/
  if (!cursor_flag){
    /* カーソル改行の必要あり？ */
    if ((x + w->overthespotWin.cursor_width) >= width){
      if ((y + w->overthespotWin.font_height) < height){
	y += w->overthespotWin.font_height ;
	line_num ++ ;
	x = w->overthespotWin.client_area.x ;
	line_top    = text ;
	linetop_pos = pos ;
	x += w->overthespotWin.cursor_width ;
	cursor_flag = True ;
      }
    } else {
      x +=  (w->overthespotWin.cursor_width) ;
      cursor_flag = True ;
    }
  }
 exit_loop:
  /* 表示すべき行数を記憶しておく。*/
  w->overthespotWin.canvas_lines = line_num + 1 ;
  /*
   *  (y - w->overthespotWin.spot_y) / w->overthespotWin.font_height + 1 ;
   */
  if (!cursor_flag){
    /* テキストを表示している途中で画面をはみでてしまい、しかもカーソ */
    /* ルはまだ登場していないというどうしようも無い状況になってしまっ */
    /* た場合…。*/
    /* フィリー「どうすのよ？ たたり！」
     * たたり  「どうするったって…やるしかないだろ？」
     */
    OTSW_ConfigureWindowsScreenIsSmall
       (gw, x, y, line_top, linetop_pos, midline_top, midline_pos) ;
    return ;
  }

  /* ここからウィンドウの再計算や配置などを行う。*/
  if (w->overthespotWin.canvas_lines == 1){
    /* まさかとは思うけど、一文字も進まなかったとかそういうんじゃない *
     * だろうねえ。*/
    if (x <= w->overthespotWin.spot_x){
      /* そうだたっら、ウィンドウは全て破棄する。*/
      XQueryPopdown
	 (gw, &w->overthespotWin.topline_probe,
	  w->overthespotWin.topline_win) ;
      XQueryPopdown
	 (gw, &w->overthespotWin.midline_probe,
	  w->overthespotWin.midline_win) ;
      XQueryPopdown
	 (gw, &w->overthespotWin.botline_probe,
	  w->overthespotWin.botline_win) ;
      w->overthespotWin.topline_width =
	w->overthespotWin.botline_width = 0 ;
      return ;
    }
    w->overthespotWin.topline_width = x - w->overthespotWin.spot_x ;
  } else {
    int width = w->overthespotWin.client_area.width - 
      w->overthespotWin.spot_x + w->overthespotWin.client_area.x ;
    /* フォント幅の倍数にならずに余ってしまう部分を捨てておく。*/
    w->overthespotWin.topline_width = width ;
  }
  w->overthespotWin.topline_text = node->textbuffer ;
  w->overthespotWin.topline_pos  = 0 ;
  w->overthespotWin.topline_x    = w->overthespotWin.spot_x ;

  XMoveResizeWindow
     (XtDisplay (gw), w->overthespotWin.topline_win,
      w->overthespotWin.topline_x, 
      w->overthespotWin.spot_y - w->overthespotWin.font_ascent,
      w->overthespotWin.topline_width,
      w->overthespotWin.font_height) ;

  if (!w->overthespotWin.topline_probe){
    XMapWindow (XtDisplay (gw), w->overthespotWin.topline_win) ;
    w->overthespotWin.topline_probe = True ;
  }

  /* 中段の処理が存在する場合の処理。*/
  if (w->overthespotWin.canvas_lines > 2){
    w->overthespotWin.midline_text = midline_top ;
    w->overthespotWin.midline_pos  = midline_pos ;

    XMoveResizeWindow
       (XtDisplay (gw), w->overthespotWin.midline_win,
        w->overthespotWin.client_area.x,
        w->overthespotWin.spot_y + w->overthespotWin.font_height - 
        w->overthespotWin.font_ascent,
        w->overthespotWin.client_area.width,
        y - w->overthespotWin.spot_y - w->overthespotWin.font_height) ;
    if (!w->overthespotWin.midline_probe){
      XMapWindow (XtDisplay (gw), w->overthespotWin.midline_win) ;
      w->overthespotWin.midline_probe = True ;
    }
  } else {
    /* 真中の窓を消去する。*/
    XQueryPopdown
       (gw, &w->overthespotWin.midline_probe, 
	w->overthespotWin.midline_win) ;
    w->overthespotWin.midline_text = NULL ;
    w->overthespotWin.midline_pos  = 0 ;
  }

  /* 下段の処理が存在する場合…。*/
  if (w->overthespotWin.canvas_lines > 1){
    w->overthespotWin.botline_width =
      x - w->overthespotWin.client_area.x ;       
    w->overthespotWin.botline_text  = line_top ;
    w->overthespotWin.botline_pos   = linetop_pos ;

    /* 座標の修正。*/
    XMoveResizeWindow
       (XtDisplay (gw), w->overthespotWin.botline_win,
        w->overthespotWin.client_area.x,
        y - w->overthespotWin.font_ascent,
        w->overthespotWin.botline_width,
        w->overthespotWin.font_height) ;
    if (!w->overthespotWin.botline_probe){
      XMapWindow (XtDisplay (gw), w->overthespotWin.botline_win) ;
      w->overthespotWin.botline_probe = True ;
    }
  } else {
    /* 最下段を閉じる。*/
    XQueryPopdown
       (gw, &w->overthespotWin.botline_probe, 
	w->overthespotWin.botline_win) ;
    w->overthespotWin.botline_text = NULL ;
    w->overthespotWin.botline_pos  = 0 ;
  }
  return ;
}

/*
 * モードウィンドウを正しい位置に移動させた挙句、中身まできちんと表示
 * してしまうという盛沢山な関数。
 */
static void OTSW_resetupModeWindow (Widget gw)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
  int x, y, min_y, max_y, min_x, max_x ;
  int modeshell_width, modeshell_height ;
  XSetWindowAttributes xswa ;

  modeshell_width  = getWidthOfModeLine
     (w->overthespotWin.fontset,
      w->overthespotWin.buffer.topbuffer,
      w->overthespotWin.buffer.jisyo_dirty,
      w->overthespotWin.buffer.overthespot_like_input) ;
  modeshell_height = w->overthespotWin.font_height ;

  /* 大きさが正しいものであるかどうかを判断する。*/
  if (w->overthespotWin.modeshell_width != modeshell_width ||
      w->overthespotWin.modeshell_height != modeshell_height){
    w->overthespotWin.modeshell_width  = modeshell_width ;
    w->overthespotWin.modeshell_height = modeshell_height ;
    XResizeWindow
       (XtDisplay (gw), w->overthespotWin.modeshell_win,
	modeshell_width, modeshell_height) ;
  }

  if (!XtIsRealized (gw))
    return ;

  /* 固定サイズのモードシェルならば、大きさの修正以上のことはしない。*/
  if (w->overthespotWin.fixed_modeshell){
    x = w->overthespotWin.status_area.x ;
    y = w->overthespotWin.status_area.y ;
  } else if (OTSW_ParseModeShellGeometry(gw)) {
    x = w->overthespotWin.modeshell_x;
    y = w->overthespotWin.modeshell_y;
  } else {
    min_x = w->overthespotWin.client_area.x ;
    min_y = w->overthespotWin.client_area.y ;
    max_x = min_x + 
      w->overthespotWin.client_area.width - modeshell_width -
      w->overthespotWin.modeshell_border_width ;
    max_y = min_y +
      w->overthespotWin.client_area.height - modeshell_height -
      w->overthespotWin.modeshell_border_width * 2 ;
    
    xswa.win_gravity = NorthWestGravity ;
    /* モードウィンドウを移動させる。*/
    if (!w->overthespotWin.botline_probe &&
	!w->overthespotWin.midline_probe){
      /* 何も文章をというか文字列を入力していなければ、カーソル位置 *
       * と同期させる。*/
      x = w->overthespotWin.spot_x ;
      y = w->overthespotWin.spot_y -
	w->overthespotWin.font_ascent + w->overthespotWin.font_height ;
    } else {
      x = w->overthespotWin.client_area.x ;
      y = w->overthespotWin.spot_y + 
	w->overthespotWin.font_height * w->overthespotWin.canvas_lines -
	w->overthespotWin.font_ascent ;
    }
    /* 左右に表示する場所があるかどうかを見る。*/
    if (x > max_x){
      x = max_x ;
    } else if (x < min_x){
      x = min_x ;
    }
    /* そのまま表示したら画面の下に出てしまう？ */
    if (y > max_y && !w->overthespotWin.south_cursor){
#ifdef DEBUG
      fprintf (stderr, "modeshell y = %d, max_y = %d\n", y, max_y) ;
      fprintf (stderr, "spot_y = %d, font_ascent = %d, font_height = %d\n",
	       w->overthespotWin.spot_y, w->overthespotWin.font_ascent,
	       w->overthespotWin.font_height) ;
      fprintf (stderr, "client y = %d, height = %d\n", 
	       w->overthespotWin.client_area.y, 
	       w->overthespotWin.client_area.height) ;
      fprintf (stderr, "border width = %d\n",
	       w->overthespotWin.modeshell_popup->core.border_width) ;
#endif
      y = w->overthespotWin.spot_y -
	w->overthespotWin.font_ascent -
	w->overthespotWin.modeshell_border_width * 2 -
	w->overthespotWin.font_height ;
      /* 画面の上から出てしまうの？ */
      if (y < min_y){
	y = w->overthespotWin.spot_y ;
	x = min_x ;
      } else {
	xswa.win_gravity = SouthWestGravity ;
      }
    }
    /* Window の Gravity を設定する。*/
    XChangeWindowAttributes
       (XtDisplay (gw), w->overthespotWin.modeshell_win,
	CWWinGravity, &xswa) ;
  }
#ifdef DEBUG
  fprintf (stderr, "modeshell (x,y) = (%d,%d) size = (%d,%d, %d)\n",
	   x, y, modeshell_width, modeshell_height, 
	   w->overthespotWin.modeshell_border_width) ;
  fprintf (stderr, "spot (x,y) = (%d,%d)\n",
	   w->overthespotWin.spot_x, w->overthespotWin.spot_y) ;
  fprintf (stderr, "client (x,y) = (%d,%d) size = (%d, %d)\n",
	   w->overthespotWin.client_area.x, 
	   w->overthespotWin.client_area.y, 
	   w->overthespotWin.client_area.width,
	   w->overthespotWin.client_area.height) ;
  fflush (stderr) ;
#endif
  /* モードウィンドウが存在していなかったら作ってしまう。*/
  if (!w->overthespotWin.modeshell_probe){
    w->overthespotWin.modeshell_probe = True ;
    XMoveWindow
       (XtDisplay (gw), w->overthespotWin.modeshell_win, x, y) ;
    XMapWindow
       (XtDisplay (gw), w->overthespotWin.modeshell_win) ;
#if 1
    XRaiseWindow(XtDisplay(gw), w->overthespotWin.modeshell_win);
#endif
  } else {
    /* 表示位置の修正をする。*/
    XMoveWindow
       (XtDisplay (gw), w->overthespotWin.modeshell_win, x, y) ;
  }
  Modeshell_Display (gw, w->overthespotWin.modeshell_win) ;
  return ;
}

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

  /* 表示形式の再計算を行う。*/
  OTSW_CalcSizeOfBufferWindows (gw) ;
  /* 再描画させる。*/
  if (w->overthespotWin.topline_probe)
    Topline_Redisplay (gw, w->overthespotWin.topline_win) ;
  if (w->overthespotWin.midline_probe)
    Midline_Redisplay (gw, w->overthespotWin.midline_win) ;
  if (w->overthespotWin.botline_probe)
    Botline_Redisplay (gw, w->overthespotWin.botline_win) ;
  /* モードウィンドウを表示する。*/
  OTSW_resetupModeWindow (gw) ;
  /* mini-buffer を表示する。*/
  OTSW_ConfigureMinibuffer (gw) ;
  return ;
}

/*
 * 表示が切れてしまった場所(*text,pos)
 */
static void OTSW_ConfigureWindowsScreenIsSmall
 (Widget gw,                  int endx, int endy,
  struct myChar *linetop,     int linetop_pos,
  struct myChar *midline_top, int midline_pos)
{
	OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
	struct SKKInputNode *node = w->overthespotWin.buffer.topbuffer ;
	int width, start_x, toppos ;
	struct myChar *toptext ;
	
	/* ここで求められた pos と text から表示すれば良い。*/
	OTSW_CalcTopPositionOfBuffer
		(w->overthespotWin.fontset,
		 linetop, linetop_pos, node->cur_pos, 
		 w->overthespotWin.client_area.width,
		 &toptext, &toppos) ;
	
	/* この場合。トップラインの大きさを決定しないといけない。*/
	{
		struct myChar *tmp_ptr = toptext ;
		int tmp_pos = toppos, cursor_flag = False ;
		
		width = 0 ;
		/* 何処まで表示すれば良いのかを計算する。*/
		while (!IS_END_OF_STRING (*tmp_ptr) &&
			   width < w->overthespotWin.client_area.width){
			if (tmp_pos == node->cur_pos)
				cursor_flag = True ;
			width += myCharTextWidth
				(w->overthespotWin.fontset, tmp_ptr, 1) ;
			tmp_ptr ++ ;
			tmp_pos ++ ;
		}
		if (!cursor_flag){
			width += w->overthespotWin.cursor_width ;
		}
	}
	/* さて、どのウィンドウを移動させたら良いのか考える。*/
	if (w->overthespotWin.canvas_lines == 1){
		if (endx <= w->overthespotWin.spot_x){
			/* そうだたっら、ウィンドウは全て破棄する。*/
			XQueryPopdown
				(gw, &w->overthespotWin.topline_probe,
				 w->overthespotWin.topline_win) ;
			XQueryPopdown
				(gw, &w->overthespotWin.midline_probe,
				 w->overthespotWin.midline_win) ;
			XQueryPopdown
				(gw, &w->overthespotWin.botline_probe,
				 w->overthespotWin.botline_win) ;
			w->overthespotWin.topline_width =
				w->overthespotWin.botline_width = 0 ;
			return ;
		}
		if ((width + w->overthespotWin.spot_x) >=
			(w->overthespotWin.client_area.x +
			 w->overthespotWin.client_area.width) || linetop_pos != toppos){
			start_x = w->overthespotWin.client_area.x ;
		} else {
			start_x = w->overthespotWin.spot_x ;
		}
		/* 絶対に入らないとかそういうことはありますか？ */
		if (width >= w->overthespotWin.client_area.width){
			width   = w->overthespotWin.client_area.width ;
		}
		/* 表示開始位置、その他もろもろの設定。*/
		w->overthespotWin.topline_width = width ;
		w->overthespotWin.topline_x     = start_x ;
		w->overthespotWin.topline_text  = toptext ;
		w->overthespotWin.topline_pos   = toppos ;
	} else {
		w->overthespotWin.topline_width =
			w->overthespotWin.client_area.width - w->overthespotWin.spot_x +
			w->overthespotWin.client_area.x ;
		w->overthespotWin.topline_x     = w->overthespotWin.spot_x ;
		w->overthespotWin.topline_text  = node->textbuffer ;
		w->overthespotWin.topline_pos   = 0 ;
	}
	XMoveResizeWindow
		(XtDisplay (gw), w->overthespotWin.topline_win,
		 w->overthespotWin.topline_x,
		 w->overthespotWin.spot_y - w->overthespotWin.font_ascent,
		 w->overthespotWin.topline_width,
		 w->overthespotWin.font_height) ;
	/* 最上段のラインを表示する窓をpopupする。*/
	if (!w->overthespotWin.topline_probe){
		XMapWindow (XtDisplay (gw), w->overthespotWin.topline_win) ;
		w->overthespotWin.topline_probe = True ;
	}
	/* 中段の処理が存在する場合の処理。*/
	if (w->overthespotWin.canvas_lines > 2){
		w->overthespotWin.midline_text = midline_top ;
		w->overthespotWin.midline_pos  = midline_pos ;
		XMoveResizeWindow
			(XtDisplay (gw), w->overthespotWin.midline_win,
			 w->overthespotWin.client_area.x,
			 w->overthespotWin.spot_y + 
			 w->overthespotWin.font_height - w->overthespotWin.font_ascent,
			 w->overthespotWin.client_area.width,
			 endy - w->overthespotWin.spot_y -
			 w->overthespotWin.font_height) ;
		if (!w->overthespotWin.midline_probe){
			XMapWindow (XtDisplay (gw), w->overthespotWin.midline_win) ;
			w->overthespotWin.midline_probe = True ;
		}
	} else {
		XQueryPopdown
			(gw, &w->overthespotWin.midline_probe, 
			 w->overthespotWin.midline_win) ;
		w->overthespotWin.midline_text = NULL ;
		w->overthespotWin.midline_pos  = 0 ;
	}
	/* 下段の処理が存在する場合…。*/
	if (w->overthespotWin.canvas_lines > 1){
		if (width >= w->overthespotWin.client_area.width){
			width   = w->overthespotWin.client_area.width ;
		}
		w->overthespotWin.botline_width = width ;
		w->overthespotWin.botline_text  = toptext ;
		w->overthespotWin.botline_pos   = toppos ;
		
		XMoveResizeWindow
			(XtDisplay (gw), w->overthespotWin.botline_win,
			 w->overthespotWin.client_area.x, 
			 endy - w->overthespotWin.font_ascent,
			 w->overthespotWin.botline_width,
			 w->overthespotWin.font_height) ;
		if (!w->overthespotWin.botline_probe){
			XMapWindow (XtDisplay (gw), w->overthespotWin.botline_win) ;
			w->overthespotWin.botline_probe = True ;
		}
	} else {
		/* 最下段を閉じる。*/
		XQueryPopdown
			(gw, &w->overthespotWin.botline_probe,
			 w->overthespotWin.botline_win) ;
		w->overthespotWin.botline_text = NULL ;
	}
	return ;
}

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

	win_gravity = NorthWestGravity ;

	/* 表示されるウィンドウの位置を修正する。これは起こす瞬間に *
	 * だけする。後は勝手に場所を指定してね。*/
	y_base = w->overthespotWin.client_y + 
		w->overthespotWin.focus_offset_y + 
		w->overthespotWin.spot_y - w->overthespotWin.font_ascent ;
	x = w->overthespotWin.client_x + w->overthespotWin.focus_offset_x ;
	
	if (!w->overthespotWin.topline_probe){
		y = y_base + w->overthespotWin.font_height ;
	} else {
		/* 最初の一行何か表示されている場合には…キャンバスに書かれてい *
		 * るものを消してしまわないように配置する。*/
		y = y_base + w->overthespotWin.font_height *
			w->overthespotWin.canvas_lines ;
	}
	/* ルートウィンドウの大きさを得る。*/
	XGetWindowAttributes
		(XtDisplay (gw),
		 RootWindowOfScreen
		 (XtScreen (w->overthespotWin.minibuffer_popup)),
		 &xwa) ;
#ifdef DEBUG
	fprintf (stderr, "Root Window Height : %d\n", xwa.height) ;
#endif
	/* ミニバッファの高さ。覚えておくべきか？ */
	mheight = w->overthespotWin.minibuffer_popup->core.border_width * 2 +
		((w->overthespotWin.change_minibuffer_font)?
		 w->overthespotWin.font_height : w->overthespotWin.mfont_height) ;
	mwidth = w->overthespotWin.minibuffer_popup->core.border_width * 2 +
		w->overthespotWin.minibuf_width ;
	
	/* この座標がミニバッファの枠の一番下の座標になる。*/
	y_lower = y + mheight ;
#ifdef DEBUG
	fprintf (stderr, "Minibuffer : y (%d) + height (%d)\n", 
			 y, mheight) ;
#endif
	/* 画面外に出てしまうの？ */
	if (y_lower > xwa.height){
		if (y_base > xwa.height){
			/* それなら画面の一番下に強制的にはっつけます。*/
			y = xwa.height - mheight -
				w->overthespotWin.minibuffer_popup->core.border_width * 2 ;
		} else {
			/* それならカーソルの上に表示しましょう。*/
			y = y_base - mheight -
				w->overthespotWin.minibuffer_popup->core.border_width * 2 ;
		}
		win_gravity = SouthWestGravity ;
	}
	/* もしかして画面の上に出てしまうということがあるのですか？ */
	if (y < 0){
		/* それなら知りません。もう画面の上に置いてしまいます。*/
		y = 0 ;
		win_gravity = NorthWestGravity ;
	}
#ifdef DEBUG
	fprintf (stderr, "Result Y = %d, y_base = %d\n", y, y_base) ;
#endif
	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->overthespotWin.minibuffer_popup),
		 &sizehints) ;
	*rx = x ;
	*ry = y ;
	return  ;
}

/*
 * クライアント窓に貼り付くタイプのミニバッファの位置と大きさの設定を
 * する関数。 
 */
static int OTSW_ConfigureSubWindowMinibuffer (Widget gw, int flag)
{
	OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
	int width, height ;

	/* まず、その左についている筈のモードシェルの大きさを見切っておく。*/
	w->overthespotWin.minibuffer_ofstx = getMaxLengthOfModeline
		(w->overthespotWin.fontset) ;
	/* 適切な大きさに変更しておく。*/
	width = w->overthespotWin.status_area.width - 
		w->overthespotWin.minibuffer_ofstx ;
	/* 正しい大きさじゃなかったら、1x1 には絶対する。*/
	height = w->overthespotWin.status_area.height ;
	if (width < 1){
		if (!flag)
			return False ;
		width = 1 ;
	}
	if (height < 1){
		if (!flag)
			return False ;
		height = 1 ;
	}
	XMoveResizeWindow
		(XtDisplay (gw), w->overthespotWin.minibuffer_win,
		 w->overthespotWin.status_area.x +
		 w->overthespotWin.minibuffer_ofstx, 
		 w->overthespotWin.status_area.y,
		 width, height) ;
	return True ;
}

/*
 * ミニバッファウィンドウの配置、大きさの設定を行う関数。
 *----
 * 大きさは実は設定してません。最初に設定したきりです。画面の内にミニ
 * バッファ窓を何処に置いたら良いのかな…と判断するに使うわけです。
 */
static void OTSW_ConfigureMinibuffer (Widget gw)
{
	OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
	struct SKKInputNode *node = w->overthespotWin.buffer.topbuffer ;
	struct SKKInputNode *mNode = w->overthespotWin.buffer.lastbuffer ;
	Window win ;
	int x, y ;
	
	if (mNode == node){
		/* 表示すべきテキストが何も無かった場合には。*/
		if (IS_END_OF_STRING (node->mtextbuffer[ 0 ])){
			/* ＰＯＰアップした状態だったら、閉じる。*/ 
			if (w->overthespotWin.minibuffer_probe){
				w->overthespotWin.minibuffer_probe = False ;
				if (w->overthespotWin.minibuffer_win == None){
					XtPopdown (w->overthespotWin.minibuffer_popup) ;
				} else {
					XUnmapWindow
						(XtDisplay (gw),w->overthespotWin.minibuffer_win) ;
				}
			}
			return ;
		}
	}
	/* ミニバッファは起きていないの？ 起きていないのだったら起こす必要 *
	 * があるよ。*/
	if (w->overthespotWin.minibuffer_win == None){
		if (!w->overthespotWin.minibuffer_probe){
			/* 指定された位置にミニバッファを移動させる。*/
			OTSW_ConfigureMinibufferPosition (gw, &x, &y) ;
			XtMoveWidget
				(w->overthespotWin.minibuffer_popup, x, y) ;
			/* Popup する。*/
			XtPopup (w->overthespotWin.minibuffer_popup, XtGrabNone) ;
		}
		win = XtWindow (w->overthespotWin.minibuffer_canvas) ;
	} else {
		x = w->overthespotWin.status_area.x +
			w->overthespotWin.minibuffer_ofstx ;
		y = w->overthespotWin.status_area.y ;
		/* minibuffer window を移動させて…。*/
		XMoveWindow
			(XtDisplay (gw), w->overthespotWin.minibuffer_win, x, y) ;
		/* minibuffer window を map する。*/
		XMapWindow (XtDisplay (gw), w->overthespotWin.minibuffer_win) ;
		
		win = w->overthespotWin.minibuffer_win ;
	}
	w->overthespotWin.minibuffer_probe = True ;
	/* キャンバスを書き直すように要求を出す。*/
	Minibuffer_Redisplay (gw, win) ;
	return ;
}    

/*
 * 以下、canvasWidget の利用する callback 達。
 */
static void Topline_Redisplay
 (Widget gw, Window win)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
  struct SKKInputNode *node = w->overthespotWin.buffer.topbuffer ;

  if (!w->overthespotWin.topline_probe)
    return ;

  XClearWindow (XtDisplay (gw), win) ;
  OTSW_FullDrawTopBufferTopLine
     (XtDisplay (gw), win,
      w->overthespotWin.fontset, 
      w->overthespotWin.gc, w->overthespotWin.rgc,
      w->overthespotWin.topline_text,
      w->overthespotWin.topline_pos,
      w->overthespotWin.font_ascent, w->overthespotWin.font_height,
      w->overthespotWin.topline_width,
       ((w->overthespotWin.botline_probe ||
	  w->overthespotWin.midline_probe ||
	 (w->overthespotWin.topline_x +
	  w->overthespotWin.topline_width) >=
	  w->overthespotWin.client_area.x + 
	  w->overthespotWin.client_area.width)? True : False),
      w->overthespotWin.cursor_width,
      node->cur_pos, node->cur_exist, w->overthespotWin.is_focus) ;
  return ;
}

static void Midline_Redisplay
 (Widget gw, Window win)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
  struct SKKInputNode *node = w->overthespotWin.buffer.topbuffer ;

  if (!w->overthespotWin.midline_probe)
    return ;
    
  XClearWindow (XtDisplay (gw), win) ;
  /* 真中の行を描画する。*/
  OTSW_FullDrawTopBufferMiddleLines
     (XtDisplay (gw), win,
      w->overthespotWin.fontset, 
      w->overthespotWin.gc, w->overthespotWin.rgc,
      w->overthespotWin.midline_text,
      w->overthespotWin.midline_pos,
      w->overthespotWin.font_ascent, w->overthespotWin.font_height,
      w->overthespotWin.client_area.width,
      w->overthespotWin.canvas_lines - 2,
      node->cur_pos, node->cur_exist, w->overthespotWin.is_focus) ;
  return ;
}

static void Botline_Redisplay
 (Widget gw, Window win)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
  struct SKKInputNode *node = w->overthespotWin.buffer.topbuffer ;

  if (!w->overthespotWin.botline_probe)
    return ;

  XClearWindow (XtDisplay (gw), win) ;
  /* 一番下の行を描画する。*/
  OTSW_FullDrawTopBufferTopLine
     (XtDisplay (gw), win,
      w->overthespotWin.fontset, 
      w->overthespotWin.gc, w->overthespotWin.rgc, 
      w->overthespotWin.botline_text,
      w->overthespotWin.botline_pos,
      w->overthespotWin.font_ascent, w->overthespotWin.font_height,
      w->overthespotWin.botline_width, 
       (w->overthespotWin.botline_width <
        w->overthespotWin.client_area.width)? False : True,
      w->overthespotWin.cursor_width,
      node->cur_pos, node->cur_exist, w->overthespotWin.is_focus) ;
  return ;
}

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

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

  if (w->overthespotWin.minibuffer_win != None){
    gc  = w->overthespotWin.gc ;
    rgc = w->overthespotWin.rgc ; 
  } else {
    gc  = w->overthespotWin.minibuf_gc ;
    rgc = w->overthespotWin.minibuf_rgc ;

    XRaiseWindow
       (XtDisplay (gw), win) ;
  }
  if (w->overthespotWin.change_minibuffer_font ||
      w->overthespotWin.minibuffer_win != None){
    fontset    = w->overthespotWin.fontset ;
    fontascent = w->overthespotWin.font_ascent ;
    fontheight = w->overthespotWin.font_height ;
  } else { 
    fontset    = w->overthespotWin.minibuf_fontset ;
    fontascent = w->overthespotWin.mfont_ascent ;
    fontheight = w->overthespotWin.mfont_height ;
  }
  XClearWindow (XtDisplay (gw), win) ;

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

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

    skkwin_jputstring
       (XtDisplay (gw), win, fontset, gc,
	0, fontascent, node->mtextbuffer) ;
  } else {

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

      if (w->overthespotWin.minibuffer_win == None){
	XWindowAttributes xwa ;
	/* ここで横幅が問題になるから…横幅を抜き出しておく。*/
	XGetWindowAttributes
	   (XtDisplay (gw), win, &xwa) ;
	width = xwa.width ;
      } else {
	width = w->overthespotWin.status_area.width -
	  w->overthespotWin.minibuffer_ofstx ;
	if (width < 1)
	  width = 1 ;
      }
      /* Window の buffer に文字列を表示する。*/
      OTSW_CalcTopPositionOfBuffer
	   (fontset, mNode->textbuffer, 0, mNode->cur_pos, width,
	    &toptext, &toppos) ;
      OTSW_FullDrawTopBufferTopLine
	 (XtDisplay (gw), win,
	  fontset, gc, rgc, 
	  toptext, toppos, fontascent, fontheight, width,
	  !IS_END_OF_STRING (mNode->textbuffer[ mNode->cur_pos ]),
	  w->overthespotWin.cursor_width,
	  mNode->cur_pos, mNode->cur_exist, 
	  w->overthespotWin.is_focus) ;
    }
  }
  XFlush (XtDisplay (gw)) ;
  return ;
}

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

/*
 * modeshell window にモードを表示をする関数。
 */
static void Modeshell_Display
 (Widget gw, Window win)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)gw ;
  unsigned long mode_status ;

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

/*
 * modeshell window の再描画をする関数。
 */
static void Modeshell_Redisplay
 (Widget gw, Window win)
{
  OverthespotWinWidget w =  (OverthespotWinWidget)gw ;

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

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

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

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

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

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

