/*							dviout for Windows
 *
 *						  main part of previewer
 *						1996, written by SHIMA & Otobe
 */

#include "dviout.h"
#include <ddeml.h>
#include <commctrl.h>
#include <shellapi.h>	/* Drag-Drop support */
#include <io.h>
#include <math.h>
#include <sys\stat.h>
#include <HtmlHelp.h>

#include "err.h"
#include "dviadd.h"
#include "floatwnd.h"
#include "key_table.h"
#include "misc_dialog.h"


/* Message Crackers */
#ifndef WM_APPCOMMAND
#define WM_APPCOMMAND 0x0319 // Intelli Mouse Explorer.
#endif

#define HANDLE_WM_USER_INITIATE(hwnd, wParam, lParam, fn) \
	((fn)((hwnd)), 0L)
#define HANDLE_WM_USER_CLEARMACRO(hwnd, wParam, lParam, fn) \
	((fn)((hwnd)), 0L)
#define HANDLE_WM_USER_EXECHYPER(hwnd, wParam, lParam, fn) \
	((fn)((hwnd), (char*)(lParam)), 0L)
#define HANDLE_WM_USER_DO_HREF(hwnd, wParam, lParam, fn) \
	((fn)((hwnd), (char*)(lParam)), 0L)
#define HANDLE_WM_USER_NEW_PAGE(hwnd, wParam, lParam, fn) \
	((fn)((hwnd), (int)(wParam)), 0L)
#define HANDLE_WM_USER_VSCROLL(hwnd, wParam, lParam, fn) \
	((fn)((hwnd), (signed int)wParam), 0L)
#define HANDLE_WM_USER_HSCROLL(hwnd, wParam, lParam, fn) \
	((fn)((hwnd), (signed int)wParam), 0L)
#define HANDLE_WM_USER_HISTORY_OPEN(hwnd, wParam, lParam, fn) \
	((fn)((hwnd), (signed int)LOWORD(wParam), (BOOL)(UINT)HIWORD(wParam)), 0L)
#define HANDLE_WM_USER_FINDNEXT(hwnd, wParam, lParam, fn ) \
	((fn)((hwnd)), 0L)
#define HANDLE_WM_USER_EXECMACRO(hwnd, wParam, lParam, fn) \
	((fn)((hwnd)), 0L)
#define HANDLE_WM_USER_FILE_OPEN(hwnd, wParam, lParam, fn) \
	((fn)((hwnd)), 0L)
#define HANDLE_WM_APPCOMMAND(hwnd, wParam, lParam, fn) \
	(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (HWND)wParam, GET_APPCOMMAND_LPARAM(lParam), GET_DEVICE_LPARAM(lParam), GET_KEYSTATE_LPARAM(lParam))
#define HANDLE_WM_TOUCH(hwnd, wParam, lParam, fn) \
	((fn)((hwnd), LOWORD(wParam), ((HTOUCHINPUT)lParam) ), 0L )

BOOL DVIWIN_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct);
void DVIWIN_OnSize(HWND hwnd, UINT state, int cx, int cy);
void DVIWIN_OnUserInitiate(HWND hwnd);
void DVIWIN_OnUserClearMacro(HWND hwnd);
void DVIWIN_OnUserExecHyper(HWND hwnd, char *szHyper);
void DVIWIN_OnUserDoHref(HWND hwnd, char* szHyper);
void DVIWIN_OnUserNewPage(HWND hwnd, int nPage);
void DVIWIN_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags);
void DVIWIN_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
void DVIWIN_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags);
void DVIWIN_OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
void DVIWIN_OnRButtonUp(HWND hwnd, int x, int y, UINT keyFlags);
void DVIWIN_OnMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
void DVIWIN_OnMButtonUp(HWND hwnd, int x, int y, UINT flags);
BOOL DVIWIN_OnSetCursor(HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg);
void DVIWIN_OnTimer(HWND hwnd, UINT id);
void DVIWIN_OnSysKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags);
void DVIWIN_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags);
void DVIWIN_OnVScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos);
void DVIWIN_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos);
void DVIWIN_OnUserVScroll(HWND hwnd, int nVScrollInc);
void DVIWIN_OnUserHScroll(HWND hwnd, int nHScrollInc);
void DVIWIN_OnChar(HWND hwnd, TCHAR ch, int cRepeat);
void DVIWIN_OnClose(HWND hwnd);
void DVIWIN_OnDestroy(HWND hwnd);
void DVIWIN_OnUserHistoryOpen(HWND hwnd, int page, BOOL bFileHistory);
void DVIWIN_OnSysCommand(HWND hwnd, UINT cmd, int x, int y);
void DVIWIN_OnUserFindNext(HWND hwnd);
void DVIWIN_OnUserExecMacro(HWND hwnd);
void DVIWIN_OnDropFiles(HWND hwnd, HDROP hdrop);
void DVIWIN_OnUserFileOpen(HWND hwnd);
void DVIWIN_OnPaint(HWND hwnd);
BOOL DVIWIN_OnAppCommand(HWND hwnd, HWND hWndClicked, int cmd, int uDevice, int dwKeys);
UINT DVIWIN_OnNCHitTest(HWND hwnd, int x, int y);
void DVIWIN_OnNCMouseMove(HWND hwnd, int x, int y, UINT codeHitTest);
void DVIWIN_OnNCLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest);
void DVIWIN_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
static BOOL GetHyperReference( char* href );
static int ExecuteHyperReference( char* href );
static int Initialized_OpenDVI( void );
static void HyperReferenceError( const char* href, int page );
static int DoHyperReference( char* href );
static int SaveHistoryAndSearchStr( void );
BOOL JumpHistory( int page, int mode, POINT pt );
void DVIWIN_OnTouch( HWND hwnd, UINT cPoints, HTOUCHINPUT hTouchInput );

// #define	USE_ETF		1
#define HYPER_2VERT	1

#define	DEF_COVER	0
#define	DEF_COVER2	1

/* VC 6.0 <shlwapi.h> */
#define WSB_PROP_VSTYLE		0x00000100L
#define WSB_PROP_HSTYLE		0x00000200L

/* VC 6.0 <commctrl.h> */
#define FSB_ENCARTA_MODE		1

#define CUR_MOV		30		// cursor moves
#define CUR_STOP	10		// cursor does't move

#ifdef MSVC
#undef MAXINT
#define	MAXINT		0x7ffffff
#endif

#define	DEB_SRCSER	0		// debug source special with string search

/* pret.c */
extern char base_href[];

extern int PrevPage; /* TODO: what? removable? */

extern char		 g_szFileName[MAX_PATH];	  // dvi-file名
extern char		 g_szFileName2[MAX_PATH];	  // 2nd dvi-file名
extern char      g_szPrevFileName[MAX_PATH];  // 直前のdvi-file名

/* prtinit.c */
extern int	f_init;
extern int	f_scr_skip;

extern int g_cyShowMessage;			/* TODO: I believe I can remove it.  */
extern BOOL g_bPrintingByDVIPRT;	/* printbmp.c */

static POINT timer_cursor_pt;		/* cursor position recorded by a timer. */

extern int f_GS;			/* epsbox.c, use eps files etc. */
extern BOOL f_gbox;			/* epsbox.c */
static int f_graphics;		/* used to control ID_GRAPHIC, and reserve f_GS and f_gsbox (only) */

extern int count_src_special;	/* pret.c, number of source special in the page. */
extern char *exec_gsrc_sp;		/* wmain.c, the name of graphic editor. */

static FINDREPLACE find_replace;		/* To keep options stable, now it is static in the scope. */

#define	PAGE_MARK	MAX_H_HIST


static char szFind[MAX_FIND_LEN+1];
static char szFindOld[MAX_FIND_LEN+1];
static UINT FindDvi;
static UINT FindPage;
static int	FindPt;
static DWORD FindFlags;
static int f_hist_msg;
static int f_searching;
static int f_rpold = -1;
static int f_rpold2 = -1;

static BOOL b_cursor_hide_by_timer_no_move = FALSE; /* TRUE if cursor is hide by a timer and still no move. */


BOOL f_seamless;
int f_FIT;				// use FIT/FULL in presentation mode
BOOL f_presenmenu;
int	f_pmenu;			// style of PresenMenu
RECT pmenu;
static POINT pmenupt;
BOOL f_pmshow;

BOOL f_flatscroll = FALSE;
int	 f_background; // 0: white 1: black 2: color 3: black back 4: white back
BOOL b_presentation_mode = FALSE;
BOOL f_dvioutspecial = TRUE;
BOOL f_srcspecial = TRUE;
BOOL f_hypertex = TRUE;
BOOL f_rev_movebutton; // 1: reverse move button.
BOOL f_DrawAnimationPointer = FALSE;
extern BOOL f_use_etf;
BOOL f_animecursor;
BOOL f_directsrc;
BOOL f_timer;
BOOL f_gedit;
int  f_secure;
BOOL f_Din;
BOOL f_macro;

BOOL f_rectcut;
RECT rectcut;

char *rectcut_org;
static RECT *p_s_invalid_rect;	/* region to be redraw, NULL means all the client region */
static BOOL f_cutedge;
BOOL f_kill=FALSE;

char sz_autosave_template[MAX_PATH] = "^f.^3d";
AUTOSAVEBMP autosavebmp = {FALSE, 0, sz_autosave_template};

char waiting_macro[MAX_MACROSIZE];	// buffer to be executed for 'timer 'wait ;
int	waiting_macro_mode;
	// 0: key  1: dviout special  2: HyperTeX dviout special  3: DDE

extern BOOL f_pagebutton;
// add a menu item to switch the style.

BOOL f_m_down = 0;
BOOL f_l_down = 0;
BOOL f_Wshow;

#ifdef	DOUBLE_PAGE
int f_2page;
int last_bmp;
static int f_2top;
BYTE *pDib2;
BYTE *p2Page;
#define	IsSecondPage(x)	(((x)-f_2page)&F_ODD2EVEN)
#endif

FARPROC g_FlatSB_SetScrollRange = NULL;
FARPROC g_FlatSB_SetScrollPos = NULL;
FARPROC g_FlatSB_SetScrollProp = NULL;
FARPROC g_InitializeFlatSB = NULL;

char *browser;
char *exec_para;
int h_hist_n;
int h_hist_pt;
struct HyperHistory h_hist[MAX_H_HIST+2];

char *texhelp;

extern BOOL f_grid;
extern BOOL f_gridO;
extern int w_grid;
extern RECT StopG0Rec; 
extern RECT StopG1Rec;

BOOL f_inch = TRUE;


static BOOL IsMouseInDVIwindow( DVI_WINDOW_PROPERTY, POINT* );
static void SetPageMoveButtons( DVI_WINDOW_PROPERTY* w );
void InitMenuItems( void );
void InitCoverWindow( void );
void AutoSaveBmp( void );
void AnimationPointer( DVI_WINDOW_PROPERTY *w, HWND hWndParent, HINSTANCE hInst, 
	int x, int y, BOOL fDraw );

SCALE scale[MAX_SCALE] =
{
	{4,4,800},
	{2,2,800},
	{6,6,800},
	{1,1,800}
};

DWORD GetFindReplaceOption()
{
	return find_replace.Flags & (FR_MATCHCASE|FR_WHOLEWORD);
}

/*
 * Called by  -sacle:  PROCEDURE
 */
void DefineScale(char *s)
{
	short num[3];
	int i, j;

	for(i = 0; i < MAX_SCALE && *s != 0; i++){
		for(j = 0; j < 3; j++){
			num[j] = (short)atoi(s);
			while(*s && *s++ != ':');
		}
		if(j < 3 || num[0] > 32 || num[1] > 32 || num[2] == 0)
			break;
		scale[i].x = num[0];
		scale[i].y = num[1];
		scale[i].gamma = num[2];
	}
}

char *hist_msg[] =
{
	"",
	"-> History",
	"-> Search",
	"-> HyperJump",
	"-> Mark",
};

enum {
	F_HM_NULL = 0,
	F_HM_HISTORY,
	F_HM_SEARCH,
	F_HM_HYPERJUMP,
	F_HM_MARK,
};

UINT	f_s_color = F_B_REDC;	/* red character */
//UINT	f_h_color = F_B_SKY;	/* light blue box */
UINT	f_h_color = 0x18060; /* change the default to blue char with ul.
 1999/11/3 by Y.OTOBE, see GetDColor() func. in tabctrl.c for detail. */

#define FreeBmp(x)	free_bmp(x - sizeof(BITMAPFILEHEADER))

void ShowBox(BYTE *pDib, struct S_BOX *box, int total, int mode)
{
	while(total-- > 0)
		ColorS_Box(pDib, box++, mode);
}

// *******  New Draw Line ******
unsigned char *pDibPen;
int PenWidth = 0;
int PenType = 0x0f; 
BOOL f_Pen = FALSE;
BOOL f_KeepDraw = FALSE;
 // 0x0f Black
 // 0x9f(blue), 0xaf(green),  0xbf(cyan), 0xcf(red), 0xdf(magenta), 0xef(yellow)
static unsigned char LineColor[16] =
{0xcf, 0x0f, 0x9f, 0xaf, 0xc4, 0x00, 0x94, 0xa4,
 0xb0, 0x00, 0xe0, 0xd0, 0xb9, 0xff, 0xe9, 0xd9};

static int PenTdata[5] = {0x0f, 0x0b, 0x08, 0x04, 0x02};

static void CheckPenBuf()
{
	if(pDibPen && !f_KeepDraw){
		FreeBmp(pDibPen);
		pDibPen = NULL;
	}
	f_KeepDraw = FALSE;
}

static BOOL DrawLine(unsigned char *pDib, int x, int y, int xx, int yy, int count, unsigned char attr)
{
	unsigned char *pt;
	WORD cxDib, cyDib;
	int px, py, pxx, pyy, wx, wy, ct, count1, count2;

	if(  pDib == NULL
	  || ((BITMAPINFOHEADER*)pDib)->biBitCount != 8			/* 256 color? */
	  || ((BITMAPINFOHEADER*)pDib)->biCompression != BI_RGB	/* compressed? */
	)
		return FALSE;
	cxDib = (WORD)((BITMAPINFOHEADER*)pDib)->biWidth;
	wx = (cxDib+3)&~3;
	cyDib = (WORD)((BITMAPINFOHEADER*)pDib)->biHeight;
	wy = cyDib-1;
	pDib += sizeof(BITMAPINFOHEADER) + 4*256;
	ct = 0;
	if(abs(xx) >= wx || abs(yy) >= wy)
		return FALSE;
#if 0
	pt = pDib + wx*(wy - y)+x;
	*pt |= 0xf;
#else
	count1 = count/2;
	count2 = (count+1)/2;
	if(abs(xx) >= abs(yy)){
		while(xx){
			pxx = x + ct;
			pyy = y + (yy*ct/xx);
			for(py = pyy - count2; py <= pyy + count1; py++){
				pt = pDib+wx*(wy-py);
				for(px = pxx-count1; px <= pxx+count2; px++){
					if(px >= 0 && px < cxDib && py >=0 && py < cyDib)
						pt[px] = attr;
				}
			}
			if(ct == xx)
				break;
			if(xx > 0)
				ct++;
			else
				ct--;
		}
	}else{
		while(1){
			pyy = y + ct;
			pxx = x + (xx*ct/yy);
			for(py = pyy - count2; py <= pyy + count1; py++){
				pt = pDib+wx*(wy-py);
				for(px = pxx-count1; px <= pxx+count2; px++){
					if(px >= 0 && px < cxDib && py >=0 && py < cyDib)
						pt[px] = attr;
				}
			}
			if(ct == yy)
				break;
			if(yy > 0)
				ct++;
			else
				ct--;
		}
	}
#endif
	return TRUE;
}

void ChangeWaitCursor(int mode)
{
	static int cond;

	if( g_winData.dviwin.loupe.bShown ) return;

	if(!cond && mode){
		ChangeMouseCursor(CS_WAIT);
		cond = mode;
	}else if(cond && !mode){
		ChangeMouseCursor(CS_NORMAL);
		cond = mode;
	}
}


//	Arrange scroll position within the correct range
static int ArrangeScroll(DVI_WINDOW_PROPERTY *w, int mode)
{
	RECT rc;
	if(!mode){
		if( w->pDib != NULL )
		{
			w->cyDib = GetDibHeight( w->pDib );
			w->cxDib = GetDibWidth( w->pDib );
#ifdef	DOUBLE_PAGE
			w->nHscrollMax = max( 0, ((IS_2HORI)?(2*w->cxDib):w->cxDib)
				- w->cxClient );
			w->nVscrollMax = max( 0, ((IS_2VERT)?(2*w->cyDib):w->cyDib)
				- w->cyClient );
#else
			w->nHscrollMax = max( 0, w->cxDib - w->cxClient );
			w->nVscrollMax = max( 0, w->cyDib - w->cyClient );
#endif
			
			/* 左右に上下に20dotsの余白をとる */
			if( w->nHscrollMax > 0 && !b_presentation_mode)
				w->nHscrollMax += 2*20;
			if( w->nVscrollMax > 0 && !b_presentation_mode)
				w->nVscrollMax += 2*20;
			
			/* DVI表示の原点を調整する */
#ifdef	DOUBLE_PAGE
			g_winData.dviwin.cxIndent = max( 0, 
			(IS_2HORI)?(w->cxClient/2 - w->cxDib):(w->cxClient - w->cxDib)/2)
							+ 20*(w->nHscrollMax > 0 && !b_presentation_mode);
			g_winData.dviwin.cyIndent = max( 0, 
			(IS_2VERT)?(w->cyClient/2 - w->cyDib):(w->cyClient - w->cyDib)/2 )
							+ 20*(w->nVscrollMax > 0 && !b_presentation_mode);

#else
			g_winData.dviwin.cxIndent = max( 0, (w->cxClient - w->cxDib)/2 )
							+ 20*(w->nHscrollMax > 0 && !b_presentation_mode);
			g_winData.dviwin.cyIndent = max( 0, (w->cyClient - w->cyDib)/2 )
							+ 20*(w->nVscrollMax > 0 && !b_presentation_mode);
#endif
		}
		else
		{
			w->nVscrollMax = 0;
			w->nHscrollMax = 0;
		}
		if(g_winData.dviwin.hWnd != NULL){
			if(g_winData.dviwin.bScrollBarShown){
				if( f_flatscroll && GetVersionLevel() > 0 )
				{
					g_FlatSB_SetScrollRange( g_winData.dviwin.hWnd, SB_VERT, 0, 
						w->nVscrollMax, FALSE );
					g_FlatSB_SetScrollPos( g_winData.dviwin.hWnd, SB_VERT, 
						w->nVscrollPos, TRUE );
					g_FlatSB_SetScrollRange( g_winData.dviwin.hWnd, SB_HORZ, 0, 
						w->nHscrollMax, FALSE );
					g_FlatSB_SetScrollPos( g_winData.dviwin.hWnd, SB_HORZ, 
						w->nHscrollPos, TRUE );
				}
				else
				{
					SetScrollRange( g_winData.dviwin.hWnd, SB_VERT, 0, 
						w->nVscrollMax, FALSE );
					SetScrollPos( g_winData.dviwin.hWnd, SB_VERT, 
						w->nVscrollPos, TRUE );
					SetScrollRange( g_winData.dviwin.hWnd, SB_HORZ, 0, 
						w->nHscrollMax, FALSE );
					SetScrollPos( g_winData.dviwin.hWnd, SB_HORZ, 
						w->nHscrollPos, TRUE );
				}
			}else{
				if( f_flatscroll && GetVersionLevel() > 0 )
				{
					g_FlatSB_SetScrollRange( g_winData.dviwin.hWnd, SB_VERT, 0, 0, FALSE );
					g_FlatSB_SetScrollRange( g_winData.dviwin.hWnd, SB_HORZ, 0, 0, FALSE );
				}
				else
				{
					SetScrollRange( g_winData.dviwin.hWnd, SB_VERT, 0, 0, FALSE );
					SetScrollRange( g_winData.dviwin.hWnd, SB_HORZ, 0, 0, FALSE );
				}
			}
		}
	}
	if(w->nVscrollMax == 0 || (w->nVscrollPos & 0x8000))
		w->nVscrollPos = 0;
	else if(w->nVscrollPos > w->nVscrollMax)
		w->nVscrollPos = w->nVscrollMax;
	if(w->nHscrollMax == 0 || (w->nHscrollPos & 0x8000))
		w->nHscrollPos = 0;
	else if(w->nHscrollPos > w->nHscrollMax)
		w->nHscrollPos = w->nHscrollMax;
	GetClientRect( w->hWnd, &rc );
	w->cxClient = rc.right - rc.left;
	w->cyClient = rc.bottom - rc.top;
	return w->nVscrollMax + w->nHscrollMax;
}


POINT GetDVICoordFromClient(const DVI_WINDOW_PROPERTY *w, int x, int y)
{
	/* Get a DVI Coordinate (in a buffer) from a client coordinate. 
	   intended to get the (unshown buffer position) from a mouse cursor position */
	POINT pt;
	pt.x = (x + w->nHscrollPos - g_winData.dviwin.cxIndent)*GetXGray();
	pt.y = (y + w->nVscrollPos - g_winData.dviwin.cyIndent)*GetYGray();
	return pt;
}

static POINT GetClientCoordFromDVI(const DVI_WINDOW_PROPERTY *w, int x, int y)
{
	/* Get a client coordinate (in DVIWIN) from a DVI buffer's coordinate. */
	POINT pt;
	pt.x = x/GetXGray() - w->nHscrollPos + g_winData.dviwin.cxIndent;
	pt.y = y/GetYGray() - w->nVscrollPos + g_winData.dviwin.cyIndent;
	return pt;
}

static void	SetScrollPosToMakePointInBufferCenterOfWindow(DVI_WINDOW_PROPERTY *w, int x, int y)
{
	/* This function only arranges the scroll position to make (x,y) place
		at the center of the client window. */
	w->nHscrollPos = x/GetXGray() - w->cxClient/2 + g_winData.dviwin.cxIndent;
	w->nVscrollPos = y/GetYGray() - w->cyClient/2 + g_winData.dviwin.cyIndent;
}

static void MoveCursorInDVICoord(const DVI_WINDOW_PROPERTY *w, int x, int y)
{
	/* Move mouse cursor to the point indicated by the buffer (DVI) coordinate. */
	POINT pt;

	pt = GetClientCoordFromDVI(w, x, y);
	ClientToScreen(g_winData.dviwin.hWnd, &pt);
	SetCursorPos(pt.x, pt.y);
}

static void ShowAtCenterAndLocateCursor(DVI_WINDOW_PROPERTY *w, int x, int y)
{
	/* Move the point in Buffer to the center of Window,
		arrange the scroll position within the correct range
		and move the cursor to the point */
	SetScrollPosToMakePointInBufferCenterOfWindow(w,x,y);
	ArrangeScroll(w, 1);
	MoveCursorInDVICoord(w,x,y);
}

//  mode = 1: bottom	2: right	4: left
static void ScrollToDVIposition(const DVI_WINDOW_PROPERTY *w, int x, int y, int mode)
{
	POINT pt;
	int xx;

	pt = GetClientCoordFromDVI(w, x, y);
	if(mode&1){							// bottom
		if(pt.y > w->cyClient)
			SendMessage( g_winData.dviwin.hWnd, WM_USER_VSCROLL, 
				pt.y - w->cyClient, 0 );
	}else if(mode&2){					// right
		if(pt.x > w->cxClient)
			SendMessage( g_winData.dviwin.hWnd, WM_USER_HSCROLL,
				pt.x - w->cxClient, 0 );
	}else if(mode&4){					// left
		xx = GetTextXSize()/GetXGray();
		if(xx > w->cxClient){
			if(pt.x < w->cxClient)
				pt.x = w->cxClient;
			SendMessage( g_winData.dviwin.hWnd, WM_USER_HSCROLL, xx - pt.x, 0 );
		}
	}
}

static void ShowFound(DVI_WINDOW_PROPERTY *w, struct S_BOX *box, 
	int total, int mode, int pos)
{
	int poss;

	if(mode & 0x100)
		ShowBox(w->pDib, box, total, mode);
	else{
		poss = pos;
		do{
			ColorS_Box(w->pDib, box + poss, mode);
		}while(++poss < total && box[poss].sub.found == box[poss-1].sub.found);
	}
	if(mode & 0x200)
		ShowAtCenterAndLocateCursor(w, box[pos].x1, box[pos].y1);
	else
		SetScrollPosToMakePointInBufferCenterOfWindow(w, box[pos].x1, box[pos].y1);
	return;
}

// Get History of page and Window data and set history pointer
void GetH_Hist(POINT *pt, int *page, int mode)
{
	int org = h_hist_pt;

	*page = 0;
	if(mode > 0){
		if(h_hist_pt != h_hist_n){
			if(++h_hist_pt == MAX_H_HIST)
				h_hist_pt = 0;
set:		if(h_hist[h_hist_pt].id == id_dvi){
				pt->x = h_hist[h_hist_pt].x;
				pt->y = h_hist[h_hist_pt].y;
				*page = h_hist[h_hist_pt].page;
			 }
		}
	}
	else if(mode < 0){
		if(	  h_hist_pt - 1 != h_hist_n
		  &&  h_hist_pt + (MAX_H_HIST) != h_hist_n){
			if(--h_hist_pt < 0)
				h_hist_pt = MAX_H_HIST - 1;
			goto set;
		}
	}else{
		h_hist_pt = h_hist_n;
		goto set;
	}
	if(!*page)
		h_hist_pt = org;
}

//	Save current page and Window position
void SaveH_Hist(DVI_WINDOW_PROPERTY *w, int mode)
{
	POINT pt;
	int i;

	if(w->pDib == NULL)
		return;
	if(!mode){
		for(i = 0; i < MAX_H_HIST; i++)
			h_hist[i].page = 0;
		h_hist_n = h_hist_pt = 0;
	}else{
		pt = GetDVICoordFromClient(w, w->cxClient/2, w->cyClient/2);
		if(mode == 1){
			if(	 h_hist[h_hist_n].page == GetCurrentPage()
			&& h_hist[h_hist_n].y == pt.y)
			return;
			if(++h_hist_n >= MAX_H_HIST)
				h_hist_n = 0;
			i = h_hist_pt = h_hist_n;
		}else
			i = mode + (MAX_H_HIST-2);
		h_hist[i].x = pt.x;
		h_hist[i].y = pt.y;
		h_hist[i].id = id_dvi;
		h_hist[i].page = GetCurrentPage();
		h_hist[i].flag = f_hist_msg;
		f_hist_msg = 0;
	}
}

//	return	>= 0 : position in Boxes
//			= -1 : not found
//
//	mode & 6 = 0 : forward	search containing (x,y)
//			   2 : forward	search after	  (x,y)
//			   4 : backward search before	  (x,y)
//
//	skip		 : number of the matched boxes to be skipped
//	total		 : total number of box[];
static int SearchS_Box(DVI_WINDOW_PROPERTY *w, struct S_BOX box[], int total,
	int x, int y, int mode, int skip)
{
	int i, val;
	POINT pt;
	POINT coverpos;

	coverpos = GetCoverPos();
	if(mode & 1){
		pt.x = x;
		pt.y = y;
	}else
		pt = GetDVICoordFromClient(w, x, y);
	if(b_presentation_mode && g_winData.dviwin.cover_sheet.fOn == CS_ON && !IS_2VERT){	// In cover sheet?
		if(pt.y >= coverpos.y){								// IS_2VERT not supported
			if(g_winData.dviwin.cover_sheet.fPlace & CS_RIGHT){
				if(pt.x + coverpos.x <= GetTextXSize())
					return -1;
			}else
				if(pt.x >= coverpos.x)
				return -1;
		}
	}
	i = (mode & 4)?total-1:0;
	while(i >= 0 && i < total){
		val = CheckS_Box(&(box[i]), pt.x, pt.y);
		if(!(mode & 6)){
			if(val == 0)
				skip--;
		}
		else if(mode & 2){
			if(val > 0)
				skip--;
		}
		else if(val < 0)
			skip--;
		if(skip < 0)
			return i;
		else if(mode & 4)
			i--;
		else i++;
	}
	return -1;
}

//	Get hypertex reference at (x,y) in Window
//	return : pointer to href
//			 NULL -> not exist
static char *GetHref(DVI_WINDOW_PROPERTY *w, int x, int y)
{
	int	  pos, found;
#if	HYPER_2VERT
	int	  page;
#endif

	if(f_2page){
		if(f_2page&(F_2PAGE|F_MPAGE|F_16PAGE) || !b_presentation_mode)
			return NULL;
#if	HYPER_2VERT
		if(IS_2VERT && pDib2){
			page = GetCurrentPage();
			if(!IsSecondPage(page))
//			if(!IS_2DIB2)
				ChgPage(page+1);
			pos = IsHyperTag();
			found = (pos>0)?SearchS_Box(w, h_box + pos + 1, h_box[pos].y0, 
				x, y-GetDibHeight(pDib2), 0, 0):-1;
			ChgPage(!IsSecondPage(page)?(page):(page-1));
//			ChgPage(!IS_2DIB2?(page):(page-1));
			if(found < 0){
				pos = IsHyperTag();
				if(pos > 0)
					found = SearchS_Box(w, h_box + pos + 1, h_box[pos].y0, 
						x, y, 0, 0);
			}
			ChgPage(page);
		}
#endif
	}else
	{
		if((pos = IsHyperTag()) <= 0)
			return NULL;
		found = SearchS_Box(w, h_box + pos + 1, h_box[pos].y0, 
			x, y, 0, 0);
	}
	return (found >= 0)?h_box[pos + found + 1].sub.href:NULL;
}

static BOOL ReplaceBmp(DVI_WINDOW_PROPERTY *w, BYTE *pDibNew)
{
	if(pDibNew == NULL)
		return FALSE;
	if(w->pDib != pDibNew + sizeof(BITMAPFILEHEADER)){
		if(w->pDib)
			FreeBmp(w->pDib);
		CheckPenBuf();
		w->pDib = pDibNew + sizeof(BITMAPFILEHEADER);
	}
	return TRUE;
}


LRESULT CALLBACK AbortSearchJob( HWND hwndDlg, UINT msg, WPARAM wParam, 
	LPARAM lParam )
{
	switch( msg )
	{
		case WM_INITDIALOG:
			return TRUE;
		case WM_COMMAND:
			f_searching = -1;
			return TRUE;
	}
	return FALSE;
}


static BOOL SetAbortSearch(int page)
{
	char szPage[16];

	if(page <= 0 || f_searching < 0){
		if(g_winData.hWndFindAbort != NULL){
/*			EnableWindow( g_winData.hMainWnd, TRUE ); */
			DestroyWindow( g_winData.hWndFindAbort );
		}
		f_searching = 0;
		g_winData.hWndFindAbort = NULL;
		return FALSE;
	}
	if(g_winData.hWndFindAbort == NULL){
		/* ダイアログボックスを作成する */
		f_searching = 1;
		g_winData.hWndFindAbort = CreateDialog( g_winData.hInstance, 
								MAKEINTRESOURCE(IDD_SEARCHABORTDIALOG),
							   g_winData.hMainWnd, (DLGPROC)AbortSearchJob );
	}
	wsprintf(szPage, "%3d(%3d) page", page, TransPage(page));
	SetDlgItemText( g_winData.hWndFindAbort, IDC_SEARCHINGPAGE, szPage );
	return TRUE;
}

static BOOL SearchStr(DVI_WINDOW_PROPERTY *w, LPFINDREPLACE lpfr, int mode)
{
	int temp_page, pos;
	int flag = 0;

	if(	 s_box_pt > 0									// Searched?
	  && FindDvi == id_dvi								// DVI?
	  && FindPage == GetCurrentPage()					// page?
	  && strcmp(szFindOld, lpfr->lpstrFindWhat) == 0	// String?
	  && (FindFlags & (FR_MATCHCASE|FR_WHOLEWORD))
		== (lpfr->Flags & (FR_MATCHCASE|FR_WHOLEWORD))){ // Flags?
find_c: if(FindPt < 0){								// Check Position
			flag = 1;
			if(lpfr->Flags & FR_DOWN)
				FindPt = 0;
			else{
				FindPt = s_box_pt;
				while(!IsTopSearchBox(--FindPt));
			}
		}
		else{
			if(!(f_s_color & 0x100)){
				pos = FindPt;
				do{
					ColorS_Box(w->pDib, s_box + pos, f_s_color & ~0xfd);
				}while(++pos < s_box_pt && !IsTopSearchBox(pos));
			}
			if(lpfr->Flags & FR_DOWN){
				do{
					if(++FindPt >= s_box_pt){
						s_box_pt = 0;
						goto find_n;
					}
				}while(!IsTopSearchBox(FindPt));
			}else{
				 do{
					if(--FindPt < 0){
						s_box_pt = 0;
						goto find_n;
					}
				}while(!IsTopSearchBox(FindPt));
			}
		}
		if(flag){
			SetColor(8);
			if(ReplaceBmp(w, MakeBMP()) == FALSE)
				goto find_not;
		}
		if(mode)
			ShowFound(w, s_box, s_box_pt, f_s_color, FindPt);
		SetAbortSearch(0);
		return TRUE;
	}else{
		f_s_search = 1;
		f_s_flags = (lpfr->Flags & FR_MATCHCASE)?0:F_S_NOCASE;
		if(lpfr->Flags & FR_WHOLEWORD)
			f_s_flags |= F_S_WORD;
		FindDvi = id_dvi;
		strcpy(szFindOld, lpfr->lpstrFindWhat);
		FindFlags = lpfr->Flags;
		SetSearchStr(szFindOld);
		SetAbortSearch(GetCurrentPage());
		ExpandPage();
find_n: FindPage = temp_page = GetCurrentPage();
		FindPt = -1;
		if(s_box_pt)
			goto find_c;
		while(mode){
			if(lpfr->Flags & FR_DOWN){
				if(FindPage == CheckPage(FindPage+1))
					break;
				FindPage++;
			}
			else{
				if(FindPage == CheckPage(FindPage-1))
					break;
				FindPage--;
			}
			f_s_search = 1;
			if(SetAbortSearch(FindPage) == FALSE)
				goto find_not;
			MessagePage(FindPage);
			ChgPage(FindPage);
			ExpandPage();
			if(s_box_pt){			/* found */
				MessagePage(0);
				goto find_c;
			}
		}
find_not:
		MessagePage(0);
		f_s_search = 0;				/* not found */
		if(temp_page != GetCurrentPage())
			ChgPage(temp_page);
		SetColor(4);
		SetAbortSearch(0);
		return FALSE;
	}
}


void EraceHistory(int his)
{
	char name[MAX_PATH], tmp[MAX_PATH+0x10], fig[4];
	int pos, count;

	strcpy(name, f_hist[his & (MAX_F_HIST - 1)].name);
	for(pos = f_hist0; pos <= his; pos++){
		if(!strcmp(f_hist[pos & (MAX_F_HIST - 1)].name, name))
			*f_hist[pos & (MAX_F_HIST-1)].name = 0;
	}
	for(pos = his-1;  pos >= f_hist0; pos--){
		if(*f_hist[pos & (MAX_F_HIST-1)].name){
			strcpy(f_hist[his & (MAX_F_HIST-1)].name,
				f_hist[pos & (MAX_F_HIST-1)].name);
			f_hist[his & (MAX_F_HIST-1)].id
				= f_hist[pos & (MAX_F_HIST-1)].id;
			f_hist[his & (MAX_F_HIST-1)].page
				= f_hist[pos & (MAX_F_HIST-1)].page;
			his--;
		}
	}
	f_hist0 = his+1;
	for(count = his = 0; count < MAX_F_KEEP; count++){
		sprintf(fig, "%d", count);
		RestoreString(tmp, MAX_PATH+0x0f, "FILE", fig, "");
		if(!*tmp)
			break;
		pos = 0;
		while(tmp[pos] == name[pos] && name[pos])
			pos++;
		if(tmp[pos] != '\t' || name[pos]){
			if(count != his){
				sprintf(fig, "%d", his);
				ReserveString("FILE", fig, tmp);
			}
			his++;				/* keep it */
		}
	}
	if(his < MAX_F_KEEP){
		sprintf(fig, "%d", his);
		ReserveString("FILE", fig, "");
	}
}


void EditFile(char *name)
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	char cmd_buf[0x400];

	if(!AskYes("Do you really want to edit the above file?", name))
		return;
	sprintf(cmd_buf, "notepad.exe %s", name);
	memset( &si, 0, sizeof(STARTUPINFO) );
	memset( &pi, 0, sizeof(PROCESS_INFORMATION) );
	si.cb = sizeof(STARTUPINFO);
	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_NORMAL;
	CreateProcess(NULL, cmd_buf, NULL, NULL, FALSE,
		HIGH_PRIORITY_CLASS, NULL, NULL, &si, &pi);	
}

HINSTANCE	ExecHref(HWND hwnd, char *href)
{
	HINSTANCE result;
	if(exec_para){
		result = 
		ShellExecute(hwnd, NULL, href, exec_para, NULL, SW_SHOWNORMAL);
		exec_para = NULL;
		return result;
	}
	return
		(browser==NULL || !*browser)?
		ShellExecute(hwnd, NULL, href, NULL, NULL, SW_SHOWNORMAL):
		ShellExecute(hwnd, NULL, browser, href, NULL, SW_SHOWNORMAL);
}

void CheckView(int size)
{
	int	pos;

	for(pos = 0; pos < 4; pos++)
		CheckMenu(ID_SCALE1+pos, pos==size);
}


#ifdef	DOUBLE_PAGE
extern int bmp_pt;

static BOOL DisplayPages(int ii)
{
	int xx, yy, pos, size;
	int old_GS, old_gbox, old_cmode, old_color;
	BYTE *pDibNew;

	if(IS_2PAGE){
		Clear2Page();
		CheckMenu(ID_DOUBLE, FALSE);
		CheckMenu(ID_RDOUBLE, FALSE);
		CheckMenu(ID_VDOUBLE, FALSE);
	}

	old_GS = f_GS;
	old_gbox = f_gbox;
	old_color = f_spcolor;
	old_cmode = f_rpcolor;
	f_GS = f_spcolor = f_rpcolor = FALSE;
	f_gbox = TRUE;

	xx = GetXGray()*ii;
	yy = GetYGray()*ii;
	f_2top = pos = GetCurrentPage();
	ExpandPage0();					// to validitate f_gbox etc..
	AddKeepBMP(0);
	ClearKeepBMP();
	for(size = 0; ;){
		pDibNew = GetWindowBMP(0, 0, GetTextXSize(), GetTextYSize(),
			xx, yy, NULL);
		if(pDibNew == NULL)
			return FALSE;
		f_GS = 1;
		DisplayBMP(pDibNew, 
			(size%ii)*GetTextXSize()/ii, (size/ii)*GetTextYSize()/ii,
			(GetTextXSize()+ii-1)/ii, (GetTextYSize()+ii-1)/ii, 1);
		f_GS = 0;
		pos = GetCurrentPage();
		AddKeepBMP(1);
		if(++size >= ii*ii || pos == ChgPage(pos + 1))
			break;
		ExpandPage0();
	}
	f_GS = old_GS;
	f_gbox = old_gbox;
	f_spcolor = old_color;
	f_rpcolor = old_cmode;
	ClearKeepBMP();
	return TRUE;
}

BYTE *Get2Bmp(void)
{
	int c_page, temp_page;
	BOOL old_dvioutspecial;

	old_dvioutspecial = f_dvioutspecial;
	f_dvioutspecial = FALSE;
	Clear2Page();
	temp_page = IsSecondPage(c_page=GetCurrentPage())?-1:1;
	if(temp_page < 0)
		f_2page |= F_2DIB2;
	else
		f_2page &= ~F_2DIB2;
	p2Page = PageDup();
	last_bmp = AddKeepBMP(1);
	pDib2 = GotoPage(GetCurrentPage() + temp_page);
	if(pDib2 == NULL){
		Free0(p2Page);
		p2Page = NULL;
	}else
		pDib2 += sizeof(BITMAPFILEHEADER);
	AddKeepBMP(0);
	f_dvioutspecial = old_dvioutspecial;
	return(pDib2);
}

static int GetShiftPage(int page)
{
	int pos;

	if(IS_2PAGE){
		pos = GetCurrentPage();
#ifdef	DOUBLE_PAGE
		if(b_presentation_mode && IS_2VERT){
			if(page == 1){
				if(pos < GetTotalPage() - 1)
					SetPoint(0,-GetTextYSize(),-3);
				ChgPage(pos-1);
				pos--;
			}else if(page == -1 && pos > 0){
				SetPoint(0,GetTextYSize(),-3);
				page = -2;
			}
			if(pos + page >= GetTotalPage() - 1)
				page = GetTotalPage() - 2;
			if(pos + page <= 0)
				page = -pos + 1;
			f_2page &= ~F_ODD2EVEN;
			if((page + pos) & 1)
				f_2page |= F_ODD2EVEN;
		}
		else 
#endif
		if(page == -1 &&
		  (pos != 2 || (IS_ODD2EVEN) != 0) )
			page = -2;
		else if(page == 1 &&
		  (pos != GetTotalPage() - 1 || !IsSecondPage(pos)) )
			page = 2;
	}
	return page;
}
#else
#define GetShiftPage(x)	(x)
#endif

void Clear2Page(void)
{
#ifdef	DOUBLE_PAGE
	if(pDib2)
		FreeBmp(pDib2);
	Free0(p2Page);
	p2Page=pDib2=NULL;
#endif
}

int timer_id;

void TempMessage(char *msg, int num)
{
	DisplayMessage(msg);
	SetTimer(g_winData.hMainWnd, 10, num, (TIMERPROC)Timer10Proc);
}


int SetStatusWindow(void)
{
	int curpage, lastpage, nombrepage;
	char szText[64];

	if(g_winData.dviwin.pDib == NULL){
		SetStatusBar( 0, "Not Opened DVI." );
		SetStatusBar( 1, "dpi:" );
		SetStatusBar( 2, "Gamma:" );
		SetStatusBar( 3, "Size:" );
		return -1;
	}
	curpage = GetCurrentPage();
	lastpage = GetTotalPage();
	nombrepage = GetMaxNombrePage();
	wsprintf( szText, "Page: %d/%d, number %d/%d",
		curpage, lastpage, TransPage(curpage), nombrepage);
	SetStatusBar( 0, szText );
	wsprintf( szText, "dpi: x=%d/%d, y=%d/%d",
		GetXDpi(), GetXGray(), GetYDpi(), GetYGray() );
	SetStatusBar( 1, szText );
	wsprintf( szText, "Gamma = %d/1000", g_winData.dviwin.gamma );
	SetStatusBar( 2, szText );
	sprintf( szText, "Size: x = %.2fcm, y = %.2fcm",
		(double)GetTextXSize()/GetXDpi()*2.54,
		(double)GetTextYSize()/GetYDpi()*2.54 );
	SetStatusBar( 3, szText );
	return curpage;
}

/*
 *  mode 0: relative under coordinate in screen
 */
void MoveCover(int x, int y, int mode)
{
	RECT rc;
	int xx, xxx, xs, xg, yy, yyy, ys, yg;

	xg = GetXGray();
	yg = GetYGray();
	xs = GetTextXSize();
	ys = GetTextYSize();

	if(!y || !(g_winData.dviwin.cover_sheet.fPlace & CS_BOTTOM))
		goto movex;
	yy = GetCoverPos().y;
	if(!mode)
		SetCoverYPos( yy + y*yg );
	else
		SetCoverYPos(y);
	if( GetCoverPos().y < 0)
		SetCoverYPos(0);
	else if(GetCoverPos().y > ys)
		SetCoverYPos(ys);
	if(GetCoverPos().y > yy)
		yyy = GetCoverPos().y;
	else if(GetCoverPos().y < yy){
		yyy = yy;
		yy = GetCoverPos().y;
	}else
		goto movex;
	if(g_winData.dviwin.cover_sheet.fPlace & CS_RIGHT){
		rc.left = g_winData.dviwin.cxIndent - g_winData.dviwin.nHscrollPos + GetCoverPos().x/xg;
		rc.right = g_winData.dviwin.cxIndent - g_winData.dviwin.nHscrollPos + xs/xg + 1;
	}else{
		rc.left = g_winData.dviwin.cxIndent - g_winData.dviwin.nHscrollPos;
		rc.right = rc.left + (xs - GetCoverPos().x)/xg + 1;
	}
	rc.top = g_winData.dviwin.cyIndent - g_winData.dviwin.nVscrollPos + yy/yg;
	rc.bottom = rc.top + (yyy - yy)/yg + 1;
	InvalidateRect( g_winData.dviwin.hWnd, &rc, FALSE );
movex:
	if(!x || !(g_winData.dviwin.cover_sheet.fPlace&0x6)) /* TODO: CHECK! is it correct? */
		return;
	xx = GetCoverPos().x;
	if(!mode){
		if(g_winData.dviwin.cover_sheet.fPlace & CS_RIGHT)
			SetCoverXPos( xx + x*xg );
		else
			SetCoverXPos( xx - x*xg );
	}else{
		if(g_winData.dviwin.cover_sheet.fPlace & CS_RIGHT)
			SetCoverXPos(x);
		else
			SetCoverXPos( xs - x );
	}
	if(GetCoverPos().x < 0)
		SetCoverXPos(0);
	else if(GetCoverPos().x > xs)
		SetCoverXPos(xs);
	if(GetCoverPos().x > xx)
		xxx = GetCoverPos().x;
	else if(GetCoverPos().x < xx){
		xxx = xx;
		xx = GetCoverPos().x;
	}else
		return;
	rc.bottom = g_winData.dviwin.cyIndent - g_winData.dviwin.nVscrollPos + ys/yg + 1;
	rc.top = g_winData.dviwin.cyIndent - g_winData.dviwin.nVscrollPos + GetCoverPos().y/yg - 1;
	if(g_winData.dviwin.cover_sheet.fPlace & CS_RIGHT)
		rc.left = g_winData.dviwin.cxIndent - g_winData.dviwin.nHscrollPos + xx/xg;
	else
		rc.left = g_winData.dviwin.cxIndent - g_winData.dviwin.nHscrollPos + (xs - xxx)/xg;
	rc.right = rc.left + (xxx - xx)/xg + 1;
	InvalidateRect( g_winData.dviwin.hWnd, &rc, FALSE );
}

static void ResetMouseMoveTimer( int n )
{
	/* 0: reset timer by the default ellapse time; 2000.
	  -1: stop the timer.
	  otherwise: set n as the timer count */
	static BOOL b_timer_on = FALSE;
	int timer_clk;
	if( n == 0 ) timer_clk = 2000;
	else timer_clk = n;

	if( b_timer_on && n == -1 ){ /* kill the timer */
		KillTimer(g_winData.dviwin.hWnd, MOUSE_NO_MOVE);
		b_timer_on = FALSE;
		return;
	}
	if( n >= 0 ){ /* start a timer */
		SetTimer(g_winData.dviwin.hWnd, MOUSE_NO_MOVE, timer_clk, NULL); /* post WM_TIMER */
		b_timer_on = TRUE;
	}
	return;
}

static void ShowCursorByMove(BOOL b)
{
	/* This is used especially for a presentation mode,
		to erase a cursor after a few (default two) seconds later the
		last mouse movement.
		If b is TRUE, it shows the cursor, otherwise hide it. */

	static CURSOR_SHAPE cs = CS_NORMAL;

	if( b && g_winData.dviwin.fCursorShape != CS_HIDE ) return;

	if( b == FALSE ){
		if( g_winData.dviwin.fCursorShape != CS_HIDE ){
			cs = g_winData.dviwin.fCursorShape;
		}
		ChangeMouseCursor(CS_HIDE);
		timer_cursor_pt.x = -1; /* to be recorded at WM_MOUSEMOVE */
		ResetMouseMoveTimer(-1); /* stop the timer. */
	} else{
		if( g_winData.dviwin.fCursorShape == CS_HIDE ){
			ChangeMouseCursor(cs);
			ResetMouseMoveTimer(0);
		}
	}
	return;
}

static void WatchMouseNoMove(void)
{
	/*
		if( !b_presentation_mode ) ResetMouseMoveTimer(-1);
	*/
	ResetMouseMoveTimer(0);
	GetCursorPos(&timer_cursor_pt);
}

/*
   MessageBox with showing cursor (presentation mode)
 */
unsigned int MessageCBox(HWND hwnd, char *title, char *msg, unsigned int id)
{
	/* I guess this function needs nothing to do
		since when a user moves the mouse, the cursor will be automatically shown...
		2012/01/15 */
	unsigned int val;
/*
	if(b_presentation_mode){
		ResetMouseMoveTimer(-1);
		ShowCursorByMove(TRUE);
	}
*/
	val = MessageBox(hwnd, title, msg, id);
/*
	if(b_presentation_mode)
		ShowCursorByMove(FALSE);
*/
	return val;
}


static VOID SaveImage(int mode, char *name)
{
	int top, bottom;
	double fx, fy, fw, fh;

	if(!f_rectcut || !mode){
		rectcut.top = 0;
		rectcut.left = 0;
		rectcut.right = GetTextXSize();
		rectcut.bottom = GetTextYSize();
	}
	if(rectcut.top > rectcut.bottom){
		top = rectcut.bottom;
		bottom = rectcut.top;
	}else{
		top = rectcut.top;
		bottom = rectcut.bottom;
	}
	fx = ((double)GetParaInt("OX")/0x10000/72.27
		- (double)rectcut.left/GetXDpi())*2.54;
	fy = ((double)GetParaInt("OY")/0x10000/72.27
		-(double)top/GetYDpi())*2.54;
	fw = (((double)(rectcut.right - rectcut.left + 1))/GetXDpi())*2.54;
	fh = (((double)(bottom - top + 1))/GetYDpi())*2.54;
	common_work[0x800] = 0;
	SetPath(common_work+0x800, common_work);
	GSPN(common_work+0x800, common_work+0x1000);
	sprintf(common_work, 
		"%s %.3fcm %.3fcm %.3fcm %.3fcm %d \"%s\" \"%s\" %d %d",
		common_work+0x1000, 
		fx+2.54, fy+2.54, fw, fh, GetCurrentPage(), 
		name, current_name,
		(int)fx, (int)fy);
	system(common_work);
}

/*
 mode 0: Inquire cutting
	  1: Execute cutting
*/
static BOOL RectCut(int mode)
{
	double fx, fy;
	int top, bottom;
	char para[0x100];

	if(!f_rectcut)
		return FALSE;
	if(  rectcut.top == 0
	  && rectcut.left == 0
	  && rectcut.right == GetTextXSize()
	  && rectcut.bottom == GetTextYSize() )
		return FALSE;
	if(!mode)
		return TRUE;

	if(rectcut.top > rectcut.bottom){
		top = rectcut.bottom;
		bottom = rectcut.top;
	}else{
		top = rectcut.top;
		bottom = rectcut.bottom;
	}
	fx = ((double)GetParaInt("OX")/0x10000/72.27
		- (double)rectcut.left/GetXDpi())*2.54;
	fy = ((double)GetParaInt("OY")/0x10000/72.27
		-(double)top/GetYDpi())*2.54;
	sprintf(para, 
		"OX=%.3fcm OY=%.3fcm y=F%ddot/%ddpi:%ddot/%ddpi",
		fx, fy,
		rectcut.right - rectcut.left + 1, GetXDpi(),
		bottom - top + 1, GetYDpi());
	SetPara(para, SET_OPTION);
	ExpandPage();
	return TRUE;
}


/*
  Set string href in common_work from search string
*/
static char *Search2Href(char *s)
{
	if(*s != ' ')
		return NULL;
	if(s[1] >= '0' && s[1] <= '9'){		// page or line number (src special)
		sprintf(common_work+0x800, "#%s", s);
		return common_work+0x800;
	}
	if(s[1] == '#'){					// HyperTeX
		strcpy(common_work+0x800, s+1);
		return common_work+0x800;
	}
	if(s[1] == '='){					// http:
		strcpy(common_work+0x800, s+2);
		return common_work+0x800;
	}
	return NULL;
}

static int CheckStop(int mode)
{
	char *s, *t, *u;
	int page;
	static char sfname[0x82];	// keep filename
	static int spage = 1;		// keep the last page
	static int slevel;			// keep the stop_level

	if(mode == 1){
		spage = 0;
		slevel = 0;
		return 0;
	}
	if(!mode){
//		it doesn't seem that stop_level may be minus.
//      stop_max ??? (if the previous page has no stop special...)
//		if((f_killstop = f_kill) == TRUE || stop_max <= 0 || stop_level < 0)
		if((f_killstop = f_kill) == TRUE )
			return 0;
	}
	s = strstr(g_szFileName, ".dvi");
	if(s == NULL)
		s = g_szFileName+strlen(g_szFileName);
	page = GetCurrentPage();
	if( (t = s - 0x80) < g_szFileName)
		t = g_szFileName;
	if(*sfname && !strncmp(t, sfname, strlen(sfname))){
											/* same dvi file */
		if(mode){
			if(page == spage && (f_killstop = f_kill) == FALSE)
				stop_level = slevel;
			return 0;
		}
		if(page < spage ){					/* the former page */
			if(page == spage - 1){
				f_killstop = FALSE;
				stop_level = slevel;
			} else
				f_killstop = TRUE;
			return 0;
		} else {								/* the same or latter page */
cnt:		if(stop_level < stop_max){
				spage = page;
				slevel = ++stop_level;
				return 1;
			}else{
				if(page < GetTotalPage()){
					spage = page+1;
					slevel = stop_level = 0;
				} else{
					/* If you press space bar at the last page... */
					spage = 1;
					slevel = stop_level = 0;
					f_killstop = FALSE;
					return 0;
				}
				return 0;
			}
		}
	}else{
		if(mode)
			return 0;
		for(u = sfname; t < s; )			/* copy filename */
			*u++ = *t++;
		*u = 0;
		spage = GetCurrentPage();
		goto cnt;
	}
}

// Window コールバック函数の本体
static BYTE *pDibKeep=NULL;
BOOL f_pDibKeep=TRUE;

static int mpty, mptx;	// Client Coordinate
static int mptyy, mptxx;	// Client Coordinate

BOOL f_h_renew = FALSE; // DVI view renewed, caused by a hyper jump.

static COLORREF pr_color;
static UINT uFindMessage;

LRESULT CALLBACK WndProc( HWND hwnd, UINT message, UINT wParam, LONG lParam )
{
	BYTE* pDibNew = NULL; 		 // DIBのﾎﾟｲﾝﾀ 
	char* href = NULL;
	static RECT rc;
	static BOOL bShowingHref = FALSE;
	static LONG wl = 0;
	static COLORREF wbk_color;
	static LONG wlc = 0;
	static int bOnHref = FALSE;
	static int bOnHrefPress = FALSE;

	if(message == uFindMessage){		/* Call back from FindText() */
		LPFINDREPLACE lpfr = (LPFINDREPLACE)lParam;
		if(lpfr->Flags & FR_FINDNEXT){
			char szText[MAX_FIND_LEN+1];
			f_hist_msg = F_HM_SEARCH;
			SaveH_Hist(&g_winData.dviwin, 1);
			if( g_winData.dviwin.pDib != NULL
				&& lpfr->lpstrFindWhat[0] == ' '){	/* hyperjump */
				sprintf(href = common_work, "#%s", lpfr->lpstrFindWhat);
				return DoHyperReference(href);
			}
			AddStringToCombo( lpfr->lpstrFindWhat );
			SetStringToCombo( lpfr->lpstrFindWhat );
			if(SearchStr(&g_winData.dviwin, lpfr, 1)) return ShowDVI(NULL, NULL);
notfound:	// pDibNew = MakeBMP();
			wsprintf( szText, "Target string = \"%s\"", szFindOld );
			ShowMessage(szText, "Not found", SM_OKCONT);
			return ReOpen(FALSE);
		}
		if(lpfr->Flags & FR_DIALOGTERM)
			g_winData.hWndFind = NULL;
	}

	switch( message ){
		HANDLE_MSG( hwnd, WM_CREATE,			DVIWIN_OnCreate );
		HANDLE_MSG( hwnd, WM_SIZE,				DVIWIN_OnSize );
		HANDLE_MSG( hwnd, WM_USER_INITIATE,		DVIWIN_OnUserInitiate );
		HANDLE_MSG( hwnd, WM_USER_CLEARMACRO,	DVIWIN_OnUserClearMacro );
		HANDLE_MSG( hwnd, WM_USER_EXECHYPER,	DVIWIN_OnUserExecHyper );
		HANDLE_MSG( hwnd, WM_USER_DO_HREF,		DVIWIN_OnUserDoHref );
		HANDLE_MSG( hwnd, WM_USER_NEW_PAGE,		DVIWIN_OnUserNewPage );
		HANDLE_MSG( hwnd, WM_MOUSEMOVE,			DVIWIN_OnMouseMove);
		HANDLE_MSG( hwnd, WM_LBUTTONDBLCLK,		DVIWIN_OnLButtonDown );
		HANDLE_MSG( hwnd, WM_LBUTTONDOWN,		DVIWIN_OnLButtonDown );
		HANDLE_MSG( hwnd, WM_LBUTTONUP,			DVIWIN_OnLButtonUp );
		HANDLE_MSG( hwnd, WM_RBUTTONDOWN,		DVIWIN_OnRButtonDown );
		HANDLE_MSG( hwnd, WM_RBUTTONUP,			DVIWIN_OnRButtonUp );
		HANDLE_MSG( hwnd, WM_MBUTTONUP,			DVIWIN_OnMButtonUp );
		HANDLE_MSG( hwnd, WM_MBUTTONDOWN,		DVIWIN_OnMButtonDown );
		HANDLE_MSG( hwnd, WM_TOUCH,				DVIWIN_OnTouch );
		HANDLE_MSG( hwnd, WM_SYSKEYDOWN,		DVIWIN_OnSysKey );
		HANDLE_MSG( hwnd, WM_SYSKEYUP,			DVIWIN_OnSysKey );
		HANDLE_MSG( hwnd, WM_KEYDOWN,			DVIWIN_OnKey );
		HANDLE_MSG( hwnd, WM_VSCROLL,			DVIWIN_OnVScroll );
		HANDLE_MSG( hwnd, WM_HSCROLL,			DVIWIN_OnHScroll );
		HANDLE_MSG( hwnd, WM_USER_VSCROLL,		DVIWIN_OnUserVScroll );
		HANDLE_MSG( hwnd, WM_USER_HSCROLL,		DVIWIN_OnUserHScroll );
		HANDLE_MSG( hwnd, WM_CHAR,				DVIWIN_OnChar );
		HANDLE_MSG( hwnd, WM_CLOSE,				DVIWIN_OnClose );
		HANDLE_MSG( hwnd, WM_DESTROY,			DVIWIN_OnDestroy );
		HANDLE_MSG( hwnd, WM_USER_HISTORY_OPEN,	DVIWIN_OnUserHistoryOpen );
		HANDLE_MSG( hwnd, WM_SYSCOMMAND,		DVIWIN_OnSysCommand );
		HANDLE_MSG( hwnd, WM_USER_FINDNEXT,		DVIWIN_OnUserFindNext );
		HANDLE_MSG( hwnd, WM_USER_EXECMACRO,	DVIWIN_OnUserExecMacro);
		HANDLE_MSG( hwnd, WM_DROPFILES,			DVIWIN_OnDropFiles);
		HANDLE_MSG( hwnd, WM_USER_FILE_OPEN,	DVIWIN_OnUserFileOpen);
		HANDLE_MSG( hwnd, WM_PAINT,				DVIWIN_OnPaint);
		HANDLE_MSG( hwnd, WM_APPCOMMAND,		DVIWIN_OnAppCommand);
		HANDLE_MSG( hwnd, WM_SETCURSOR,			DVIWIN_OnSetCursor);
		HANDLE_MSG( hwnd, WM_TIMER,				DVIWIN_OnTimer);
		HANDLE_MSG( hwnd, WM_NCHITTEST,			DVIWIN_OnNCHitTest);
		HANDLE_MSG( hwnd, WM_NCMOUSEMOVE,		DVIWIN_OnNCMouseMove);
		HANDLE_MSG( hwnd, WM_NCLBUTTONDOWN,		DVIWIN_OnNCLButtonDown);
		HANDLE_MSG( hwnd, WM_COMMAND,			DVIWIN_OnCommand);
	}
	return DefWindowProc( hwnd, message, wParam, lParam );
}

BOOL DVIWIN_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{
	/* Called BEFORE CreateWindow(Ex) returns.
		After the window is created, but before the window becomes visible. */
	g_winData.hInstance = lpCreateStruct->hInstance;
	memset(&find_replace, 0, sizeof(FINDREPLACE));
	uFindMessage = RegisterWindowMessage(FINDMSGSTRING);
	find_replace.lStructSize = sizeof(FINDREPLACE);
	g_winData.dviwin.bHand = FALSE;
	g_winData.dviwin.bDragging = FALSE;
	g_winData.dviwin.fCoverMoveDir = NO_MOVE;
	g_winData.dviwin.bCapture = FALSE;
	g_winData.dviwin.loupe.bShown = FALSE;
	DragAcceptFiles( hwnd, TRUE); 
	return TRUE;
	/* TRUE continues to create the window. FALSE destroys the window.
	   (different from the behaviour of WM_CREATE) see the definition in WindowsX.h  */
}

void DVIWIN_OnSize(HWND hwnd, UINT state, int cx, int cy)
{
	/* state:
		SIZE_MAXIMIZED: Window has been maximized. 
		SIZE_MINIMIZED: Window has been minimized. 
		SIZE_RESTORED:  Window has been resized, but neither SIZE_MINIMIZED nor SIZE_MAXIMIZED applies. 
		SIZE_MAXHIDE:   Message is sent to all pop-up windows when some other window is maximized. 
		SIZE_MAXSHOW:   Message is sent to all pop-up windows when some other window has been restored to its former size.
	 */
	g_winData.dviwin.cxClient = cx;
	g_winData.dviwin.cyClient = cy;
	ArrangeScroll(&g_winData.dviwin, 0);
	return;
}

void DVIWIN_OnUserInitiate(HWND hwnd)
{
	RECT rc;
	int pos;

	NotifyDviinfo(&g_winData.dviwin);
	GetClientRect( g_winData.dviwin.hWnd, &rc );
	/* Modify scrollbar style */
	g_winData.dviwin.cxClient = rc.right - rc.left;
	g_winData.dviwin.cyClient = rc.bottom - rc.top;
	if( f_flatscroll && GetVersionLevel() > 0 ){
		g_InitializeFlatSB( g_winData.dviwin.hWnd );
		g_FlatSB_SetScrollProp( g_winData.dviwin.hWnd, WSB_PROP_VSTYLE,
			FSB_ENCARTA_MODE,
			 TRUE );
		g_FlatSB_SetScrollProp( g_winData.dviwin.hWnd, WSB_PROP_HSTYLE,
			FSB_ENCARTA_MODE,
			 TRUE );
		g_FlatSB_SetScrollRange( g_winData.dviwin.hWnd, SB_VERT, 0, 0, TRUE );
		g_FlatSB_SetScrollRange( g_winData.dviwin.hWnd, SB_HORZ, 0, 0, TRUE );
	} else {
		SetScrollRange( g_winData.dviwin.hWnd, SB_VERT, 0, 0, TRUE );
		SetScrollRange( g_winData.dviwin.hWnd, SB_HORZ, 0, 0, TRUE );
	}

	pos = !(f_hyper & F_H_IGNORE)?TRUE:FALSE;
	SendMessage( g_winData.toolbar.hWndToolBar, TB_CHECKBUTTON, ID_HYPER, MAKELONG(pos,0));
	EnableMenuItem( g_winData.hMenu, ID_HYPERTEX, pos?MF_ENABLED:MF_GRAYED );
	EnableMenuItem( g_winData.hMenu, ID_SRCSPECIAL, pos?MF_ENABLED:MF_GRAYED );
	if(g_szLogFileName != NULL && *g_szLogFileName != '-')
	g_bLog = TRUE;
	CheckMenu(ID_LOGOPEN, g_bLog);
	find_replace.Flags = RestoreInt( "FIND", "flag", FR_MATCHCASE|FR_WHOLEWORD)
	 |FR_DOWN;
	find_replace.wFindWhatLen = MAX_FIND_LEN;
	find_replace.hwndOwner = g_winData.dviwin.hWnd;	
		/* コードの構成をいじらない（だけの）ために
		親ウィンドウはDVIウィンドウにしておく */
	find_replace.lpstrFindWhat = szFind;
	g_winData.dviwin.fCursorShape = CS_NORMAL;
	InitMenuItems();
	return;
}

void DVIWIN_OnUserClearMacro(HWND hwnd)
{
	id_current_macro = 0;
	if(timer_id)
		KillTimer(g_winData.hMainWnd, 7);
	timer_id = 0;
	return;
}

void DVIWIN_OnUserExecHyper(HWND hwnd, char *szHyper)
{
	char* href;
	strcpy(href = common_work + 0x2000, szHyper);
	Free0(szHyper);
	ExecuteHyperReference(href);
	return;
/*
hpjp:	if( GetHyperReference(href) )
hpjp0:	return ExecuteHyperReference( href );
*/
}

void DVIWIN_OnUserDoHref(HWND hwnd, char *szHyper)
{
	/* I guess this message is called only when opened via dde,
		and then, in the former code, szHyper looks indefinite?
		Now it should be NULL since szHyper (lParam) is always 0. */
do_href:
	DoHyperReference(szHyper);
	return;
}

void DVIWIN_OnUserNewPage(HWND hwnd, int nPage)
{
	/* temp_page = nPage; */
	BYTE* pDibNew;
	if(g_winData.dviwin.pDib != NULL){
		SaveH_Hist(&g_winData.dviwin, 1);
		pDibNew = (BYTE*)GotoPage(nPage);
		RenewDVI( &pDibNew, NULL );
	}
	return;
}

int SetDraggingCursorShape( void )
{
	POINT pt;
	CURSOR_SHAPE new_cs;

	assert( g_winData.dviwin.bDragging && g_winData.dviwin.bCapture );

	if( g_winData.dviwin.fCursorShape == CS_HIDE ){
		return ChangeMouseCursor(CS_HIDE);
	}

	switch(g_winData.dviwin.fCoverMoveDir){
		case VERTICAL_MOVE:
			new_cs = CS_NS_ARROW;
			break;
		case HORIZONTAL_MOVE:
			new_cs = CS_WE_ARROW;
			break;
		case (VERTICAL_MOVE + HORIZONTAL_MOVE):
			new_cs = CS_ALL_ARROW;
			break;
		default: // NO_MOVE (The coversheet is not moving)
			if( f_Pen ) new_cs = CS_NORMAL;
			else{
				if( b_presentation_mode ){
					new_cs = (g_winData.dviwin.bHand)?CS_LASER_HAND:CS_NORMAL;
				} else{
					new_cs = (g_winData.dviwin.bHand)?CS_MOVING_HAND:CS_NORMAL;
				}
			}
			break;
	}

	assert( g_winData.dviwin.bCapture );
	if( g_winData.dviwin.fCursorShape != CS_HIDE && new_cs != g_winData.dviwin.fCursorShape ){
		ChangeMouseCursor(new_cs);
		if(g_winData.dviwin.fCoverMoveDir){
			if(g_winData.dviwin.fCoverMoveDir & VERTICAL_MOVE)
				pt.y = GetCoverPos().y/GetYGray() - g_winData.dviwin.nVscrollPos
					+ g_winData.dviwin.cyIndent;
			if(g_winData.dviwin.fCoverMoveDir & HORIZONTAL_MOVE){
				if(g_winData.dviwin.cover_sheet.fPlace & CS_RIGHT)
					pt.x = GetCoverPos().x/GetXGray() - g_winData.dviwin.nHscrollPos
						+ g_winData.dviwin.cxIndent;
				else if(g_winData.dviwin.cover_sheet.fPlace & CS_LEFT)
					pt.x = (GetTextXSize() - GetCoverPos().x)/GetXGray()
						- g_winData.dviwin.nHscrollPos + g_winData.dviwin.cxIndent;
			}
			mptxx = mptx;
			mptyy = mpty;
			if( pt.x >= 0 && pt.x <= g_winData.dviwin.cxClient
			 && pt.y >= 0 && pt.y <= g_winData.dviwin.cyClient
			 && ( mptx != pt.x || mpty != pt.y) ){
				mptx = pt.x;
				mpty = pt.y;
				ClientToScreen(g_winData.dviwin.hWnd, &pt);
				SetCursorPos(pt.x, pt.y);
			}
		}
	}
	return (g_winData.dviwin.bDragging = TRUE);
}


void DVIWIN_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
{
/*
	KeyFlags: MK_CONTROL, MK_LBUTTON, MK_MBUTTON, MK_RBUTTON, MK_SHIFT,
		MK_XBUTTON1, MK_XBUTTON2, <- X button 1 and 2 of the IntelliMouse.
*/
	POINT pt;
	int pos;
	char* tmpname;
	RECT rc;
	char* href;
	BOOL bOnHrefPress;

	if( fDoubleClick ){
		if(g_winData.dviwin.pDib == NULL) return;
		if(IS_MPAGE){
			SelectPage( x, y );
			return;
		}
		if (b_presentation_mode && (g_winData.dviwin.cover_sheet.fButton & CS_LBUTTON))
			return;
		pt = GetDVICoordFromClient(&g_winData.dviwin, x, y);
		pos = IsHyperTag();
		if(	(pos = IsHyperTag()) > 0 && GetS_Count(0) ){
			PickUpString(pt.x, pt.y, 2);
			ExpandPage();
		}
		if(exec_gsrc_sp && exec_gsrc_sp[0] && f_gedit){
			tmpname = GetFigurePath(pt.x, pt.y, 1);
			if(tmpname)
				ToGSource(tmpname);
		}
		return;
	} else{ /* Single click (just button down)*/
		f_l_down = 1;
		if( g_winData.dviwin.loupe.bShown == TRUE || !IsMouseInDVIwindow(g_winData.dviwin, &pt) ) return;
		SetFocus( g_winData.dviwin.hWnd );

		if(b_presentation_mode && (g_winData.dviwin.cover_sheet.fButton & CS_LBUTTON)){
			DownPage();
			return;
		}
		
		if( f_hypertex && (href = GetHref(&g_winData.dviwin, x, y)) != NULL ){
			bOnHrefPress = TRUE;
			ChangeMouseCursor(CS_POINT_PUSH);
			return;
		}

		/* If clicked with SHIFT key, */
		if( keyFlags & MK_SHIFT ){
			if(g_winData.dviwin.pDib != NULL){
				pt = GetDVICoordFromClient(&g_winData.dviwin, x, y);
				if(f_rectcut){
					if(b_presentation_mode){
						if( keyFlags & MK_CONTROL ) SetPoint(pt.x, pt.y, 0x80);
						else{
							SetPoint(pt.x, pt.y, 0);
							rc.left = x - 4;
							rc.right = x + 4;
							rc.top = y - 4;
							rc.bottom = y + 4;
							p_s_invalid_rect = &rc;
						}
					} else if(pt.x <= rectcut.right){ /* if( b_presentation_mode ) */
						rectcut.left = pt.x;
						rectcut.top = pt.y;
					}
					ShowDVI(NULL, NULL);
					return;
				}
				PickUpString(pt.x, pt.y, (keyFlags & MK_CONTROL)?1:(f_directsrc?2:0));
				ExpandPage();
			}
			return;
		}

		/* We check whether mouse cursor is "hand" mode.
		   if "hand" mode, it means that users want to scroll. */
		if( g_winData.dviwin.bHand || f_Pen ){
			if( g_winData.dviwin.bHand ){
				ChangeMouseCursor( (b_presentation_mode)?CS_LASER_HAND:CS_MOVING_HAND );
				SetCapture( g_winData.dviwin.hWnd );
				g_winData.dviwin.bCapture = TRUE;
			}
			mptx = pt.x, mpty = pt.y;
			if(	   b_presentation_mode 
				&& g_winData.dviwin.cover_sheet.fOn == CS_ON
				&& !f_2page
				&& g_winData.dviwin.nVscrollMax == 0
				&& g_winData.dviwin.nHscrollMax == 0 ){
cover_on:		g_winData.dviwin.fCoverMoveDir = g_winData.dviwin.cover_sheet.fPlace & VERTICAL_MOVE;
				if(g_winData.dviwin.cover_sheet.fPlace & (CS_RIGHT | CS_LEFT))
					g_winData.dviwin.fCoverMoveDir |= HORIZONTAL_MOVE;
			}
		} else if(IS_MPAGE){
			SelectPage( x, y );
			return;
		}
	} /* Single click. */
	return;
}

void DVIWIN_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
{
	/* Posted if the mouse moves on a window, or captured by the window.
		KeyFlags: MK_CONTROL, MK_LBUTTON, MK_MBUTTON, MK_RBUTTON, MK_SHIFT,
			MK_XBUTTON1, MK_XBUTTON2, <- ??? what are these?
		x, y: coordinte of the cursor; relative to the upper-left corner of the client area. */

	/* TODO: For me, it looks to move a loupe is slow in the presentation mode. why? */

	BOOL bOnHref, bOnHrefPress;
	char* href;
	static BOOL bShowingHref;
	int xx, yy;
//	static int mptx = -1, mpty = -1;

	if( keyFlags & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON) )
		g_winData.dviwin.bDragging = TRUE;
	else
		g_winData.dviwin.bDragging = FALSE;

	bOnHref = (href = GetHref(&g_winData.dviwin, x, y))?TRUE:FALSE;
	if( bOnHref && (keyFlags & MK_LBUTTON) ) bOnHrefPress = TRUE;
	else bOnHrefPress = FALSE;

	/* If the loupe is not shown WITHOUT the cursor */
	if( b_presentation_mode ){
		if( g_winData.dviwin.fCursorShape == CS_HIDE && 
			!(g_winData.dviwin.loupe.bShown && g_winData.dviwin.loupe.bKillCursor) ){
			/* Mouse moves but first move after hidden by a timer, or very small move. */
			if(timer_cursor_pt.x == -1){
				timer_cursor_pt.x = x;
				timer_cursor_pt.y = y;
			} else if( fabs(timer_cursor_pt.x - x) > CUR_MOV || fabs(timer_cursor_pt.y - y) < CUR_MOV ){
				ShowCursorByMove(TRUE);
			}
		} else{
			ResetMouseMoveTimer(0);
		}
	}

	/* LOUPE is shown */
	if( g_winData.dviwin.loupe.bShown == TRUE ){
		#define	SKIP	4
		POINT pt;

		assert( g_winData.dviwin.bCapture == TRUE );
		assert( g_winData.dviwin.bDragging == TRUE );
		GetCursorPos( &pt );
		if( IsMouseInDVIwindow(g_winData.dviwin, &pt) ){
			ClientToScreen( g_winData.dviwin.hWnd, &pt );
			if( mptx - pt.x >= g_winData.dviwin.loupe.skip
			 || pt.x - mptx >= g_winData.dviwin.loupe.skip
			 || mpty - pt.y >= g_winData.dviwin.loupe.skip
			 || pt.y - mpty >= g_winData.dviwin.loupe.skip ){
				RECT deskrc;
				int lptx, lpty;
				g_winData.dviwin.loupe.bDrawing = TRUE;
				mptx = pt.x, mpty = pt.y;
				if(g_winData.dviwin.loupe.fShape & F_LEDGE){
					GetWindowRect(GetDesktopWindow(), (LPRECT)&deskrc);
					if (pt.x - (signed int)g_winData.dviwin.loupe.diam/2 < deskrc.left)
					  lptx = deskrc.left;
					else if (pt.x + g_winData.dviwin.loupe.diam/2 > deskrc.right)
					  lptx = deskrc.right - g_winData.dviwin.loupe.diam;
					else
					  lptx = pt.x - g_winData.dviwin.loupe.diam/2;
					if (pt.y - (signed int)g_winData.dviwin.loupe.diam/2 < deskrc.top)
					 lpty = deskrc.top;
					else if (pt.y + g_winData.dviwin.loupe.diam/2 > deskrc.bottom)
					  lpty = deskrc.bottom - g_winData.dviwin.loupe.diam;
					else
					  lpty = pt.y - g_winData.dviwin.loupe.diam/2;
				}else{
					lptx = pt.x - g_winData.dviwin.loupe.diam/2;
					lpty = pt.y - g_winData.dviwin.loupe.diam/2;
				}
				SetWindowPos( g_winData.dviwin.loupe.hWnd,
					HWND_TOPMOST,
					lptx, lpty, 
					g_winData.dviwin.loupe.diam, g_winData.dviwin.loupe.diam,
					SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOCOPYBITS );
				g_winData.dviwin.loupe.bDrawing = FALSE;
				InvalidateRect( g_winData.dviwin.loupe.hWnd, NULL, FALSE );
				if( g_winData.dviwin.loupe.bKillCursor ){
					ChangeMouseCursor(CS_HIDE);
				} 
			}
		} else{// loupe shown, if( IsMouseInDVIwindow(g_winData.dviwin, &pt) )
			if( g_winData.dviwin.bCapture ){
				ReleaseCapture();
				g_winData.dviwin.bCapture = FALSE;
				g_winData.dviwin.bDragging = FALSE;
			}
			ShowWindow( g_winData.dviwin.loupe.hWnd, SW_HIDE );
			if(g_winData.dviwin.fCursorShape == CS_HIDE){
				ChangeMouseCursor(CS_PREV);
			}
			g_winData.dviwin.loupe.bShown = FALSE;
		} // if( IsMouseInDVIwindow(g_winData.dviwin, &pt) )
		return;
	}

	/* Show a presentation menu in a presentation mode. */
	if(b_presentation_mode && g_winData.hWndPresenMenu){
		GetWindowRect(g_winData.hWndPresenMenu, &pmenu);
		if( x+CUR_MOV >= pmenu.left && y <= pmenu.right+CUR_MOV && 
			y+CUR_MOV >= pmenu.top  && y <= pmenu.bottom+CUR_MOV ){
			if(!f_pmshow){
				ShowWindow(g_winData.hWndPresenMenu, SW_SHOW);
				f_pmshow = TRUE;
			}
		}else if(f_pmshow && (pmenu.left || pmenu.top) ){
			ShowWindow(g_winData.hWndPresenMenu, SW_HIDE);
			f_pmshow = FALSE;
		}
	}

	/* Check the mouse cursor is on a hyper ref. */
	assert( g_winData.dviwin.loupe.bShown == FALSE );
	if( bOnHref && f_hypertex ){
		static POINT loc_cur;
		static char *loc_href;

		ChangeMouseCursor( bOnHrefPress?CS_POINT_PUSH:CS_POINT );
		if( (loc_cur.x != x || loc_cur.y != y) || bShowingHref != TRUE){
			if(!bShowingHref || loc_href != href){
				ShowHyperLink( href );
				bShowingHref = TRUE;
				loc_href = href;
			}
			loc_cur.x = x;
			loc_cur.y = y;
		}
		mptx = x;
		mpty = y;
		return;
	} else{ // mouse is not on the hyper ref or hypertex is disabled.
		CURSOR_SHAPE cs;
		if( b_presentation_mode ){
			if( g_winData.dviwin.bHand ) cs = CS_LASER_HAND;
			else cs = CS_POINTER;
		} else{
			if( g_winData.dviwin.bHand ) cs = CS_HAND;
			else cs = CS_NORMAL;
		}
		ChangeMouseCursor( cs );
		if( bShowingHref != FALSE )	ShowHyperLink( NULL );
		bShowingHref = FALSE;
	}
		
	if( GetForegroundWindow() != g_winData.hMainWnd ) return; /* TODO: Is this needed? */
			
	assert( g_winData.dviwin.loupe.bShown == FALSE );
	if( (g_winData.dviwin.bHand || f_Pen) ){
		/* scroll_by_hand mode, or pen is valid. */
		POINT pt;
		if( IsMouseInDVIwindow(g_winData.dviwin, &pt) ){
			if( g_winData.dviwin.bDragging == TRUE ){
				if( !g_winData.dviwin.bCapture ){
					SetCapture( g_winData.dviwin.hWnd );
					g_winData.dviwin.bCapture = TRUE;
				}
				SetDraggingCursorShape();
				if( !g_winData.dviwin.bHand ){
					if(g_winData.dviwin.pDib &&(mptx != pt.x || mpty != pt.y)){
						unsigned char *pD;
						RECT rcc;
					
						if(pDibPen == NULL){
							pD = g_winData.dviwin.pDib-sizeof(BITMAPFILEHEADER);
							if((((BITMAPINFOHEADER*)g_winData.dviwin.pDib)->biBitCount) != 8){
								SetColor(8);
								ReplaceBmp(&g_winData.dviwin, MakeBMP());
								if(g_winData.dviwin.pDib==NULL) return;
								pD = g_winData.dviwin.pDib-sizeof(BITMAPFILEHEADER);
							}
							pDibPen = (unsigned char *)marea(((BITMAPFILEHEADER*)pD)->bfSize);
							if(pDibPen){
								memset(pDibPen, (SetGamma(0)>0)?0:0xf, ((BITMAPFILEHEADER*)pD)->bfSize);
								memcpy(pDibPen, pD, ((BITMAPFILEHEADER*)pD)->bfOffBits);
								pDibPen += sizeof(BITMAPFILEHEADER);
							}
						}
						else if((WORD)((BITMAPINFOHEADER*)g_winData.dviwin.pDib)->biWidth != (WORD)((BITMAPINFOHEADER*)pDibPen)->biWidth
								|| IS_MPAGE  || HIBYTE(GetKeyState(VK_SHIFT)) )
							goto skipdraw;
						if(!b_presentation_mode){
							xx = PenWidth;
							yy = PenType;
							if((yy & 0xf) < 8)
								xx = xx*2+1;
						}else{
							xx = g_winData.draw_color & 3;
							if(g_winData.draw_style)
								xx |= 4;
							if(SetGamma(0) > 0)
								yy = LineColor[xx];
							else
								yy = LineColor[xx|8];
							xx = (g_winData.draw_color & F_DTHICK)?1:0;
							if(g_winData.draw_style){
								xx = xx?9:5;
							}
						}
						DrawLine(pDibPen, mptx + g_winData.dviwin.nHscrollPos - g_winData.dviwin.cxIndent, mpty+ g_winData.dviwin.nVscrollPos - g_winData.dviwin.cyIndent, 
							pt.x-mptx, pt.y-mpty, xx, yy);
						if(pt.x > mptx){
							rcc.left = mptx-xx/2;
							rcc.right = pt.x+(xx+3)/2;
						}else{
							rcc.left = pt.x-xx/2;
							rcc.right = mptx+(xx+3)/2;
						}
						if(pt.y > mpty){
							rcc.top = mpty-(xx+1)/2;
							rcc.bottom = pt.y+xx/2+1;
						}else{
							rcc.top = pt.y-(xx+1)/2;
							rcc.bottom = mpty+xx/2+1;
						}
						InvalidateRect( g_winData.dviwin.hWnd, &rcc, FALSE );
skipdraw:				mptx = pt.x;
						mpty = pt.y;
					}
					return;
				} // if( !g_winData.dviwin.bHand )
				if( mpty != pt.y ){
					short nVscrollInc = (short)(mpty - pt.y);
					mpty = pt.y;
					/* it is important that flow returns here after finishing scroll. */
					SendMessage( hwnd, WM_USER_VSCROLL, nVscrollInc, 0 );
				}
				if( mptx != pt.x ){
					short nHscrollInc = (short)mptx - pt.x;
					mptx = pt.x;
					SendMessage( hwnd, WM_USER_HSCROLL, nHscrollInc, 0 );
				}
			}  else{ // if( g_winData.dviwin.bDragging == TRUE )
				if( g_winData.dviwin.fCursorShape != CS_HAND ){
					ChangeMouseCursor(CS_HAND);
				}
			}
		} else{ // if( IsMouseInDVIwindow(g_winData.dviwin, &pt) )
			/* mouse is hand mode but not in DVI window. */
			if( g_winData.dviwin.bDragging == TRUE ){
				if( g_winData.dviwin.fCursorShape != CS_MOVING_HAND ){
					ChangeMouseCursor(CS_MOVING_HAND);
				}
				if(g_winData.dviwin.fCoverMoveDir){
					MoveCover(pt.x - mptx, pt.y - mpty, 0);
					mptx = pt.x;
					mpty = pt.y;
					return;
				}
				if( mpty != pt.y ){
					short nVscrollInc = (short)(mpty - pt.y);
					mpty = pt.y;
					SendMessage( hwnd, WM_USER_VSCROLL, nVscrollInc, 0 );
				}
				if( mptx != pt.x ){
					short nHscrollInc = (short)(mptx - pt.x);
					mptx = pt.x;
					SendMessage( hwnd, WM_USER_HSCROLL, nHscrollInc, 0 );
				}
			} else{// if( g_winData.dviwin.bDragging == TRUE )
				if( g_winData.dviwin.bCapture ){
					ReleaseCapture();
					g_winData.dviwin.bCapture = FALSE;
				}
				ChangeMouseCursor(CS_NORMAL);
				SendMessage( hwnd, WM_LBUTTONUP, 0, 0 );
			}
		} // if( IsMouseInDVIwindow(g_winData.dviwin, &pt) ) 
	} // if( g_winData.dviwin.bHand || f_Pen )
}

void DVIWIN_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
{
	char* href;
	POINT pt;
lbup:
	f_l_down = FALSE;

	if(b_presentation_mode){
		ChangeMouseCursor(g_winData.dviwin.bHand?CS_LASER_HAND:CS_POINTER);
	} else{
		ChangeMouseCursor(g_winData.dviwin.bHand?CS_HAND:CS_NORMAL);
	}

	if( (g_winData.dviwin.bHand || f_Pen) && g_winData.dviwin.bDragging == TRUE){
		g_winData.dviwin.bDragging = FALSE;
		if(g_winData.dviwin.fCoverMoveDir){
			pt.x = mptxx;
			pt.y = mptyy;
			ClientToScreen(g_winData.dviwin.hWnd, &pt);
			SetCursorPos(pt.x, pt.y);
			g_winData.dviwin.fCoverMoveDir = NO_MOVE;
		}
	}

	if( f_hypertex && (href = GetHref(&g_winData.dviwin, x, y)) != NULL ){
//		bOnHrefPress = FALSE;
		exec_para = NULL;
		ChangeMouseCursor(CS_POINT);
		if( href ){
			if( GetHyperReference(href) ) ExecuteHyperReference(href);
		}
	}
	if( g_winData.dviwin.bCapture ){
		ReleaseCapture();
		g_winData.dviwin.bCapture = FALSE;
	}
	g_winData.dviwin.bDragging = FALSE;
	return;
}

void DVIWIN_OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
{
	POINT pt;
	char* tmpname;
	int pos;

	if( f_l_down && count_src_special && !f_2page && (keyFlags & MK_CONTROL) ){
		if(g_winData.dviwin.pDib != NULL){
			pt = GetDVICoordFromClient(&g_winData.dviwin, x, y);
			tmpname = GetWPos2Source(&pt, &pos);
			if(tmpname != NULL && !ToSource(&tmpname, pos)){
					error(C_MSG, "%s : %d", tmpname, pos);
					error(DATATITLE, "source special");
			}
		}
		SendMessage(hwnd, WM_LBUTTONUP, (WPARAM)(UINT)keyFlags, MAKELPARAM(x,y));
		return;
	}

	if( g_winData.dviwin.bDragging == TRUE ){
		if(b_presentation_mode && (g_winData.dviwin.cover_sheet.fOn == CS_ON) && !f_2page
		  && !g_winData.dviwin.fCoverMoveDir){
			if(IsMouseInDVIwindow( g_winData.dviwin, &pt ) & IN_CLIENT){
				mptx = pt.x, mpty = pt.y;
				g_winData.dviwin.fCoverMoveDir = g_winData.dviwin.cover_sheet.fPlace & VERTICAL_MOVE;
				if(g_winData.dviwin.cover_sheet.fPlace & (CS_RIGHT | CS_LEFT))
					g_winData.dviwin.fCoverMoveDir |= HORIZONTAL_MOVE;
				SetDraggingCursorShape();
			}
		}
		return;
	}

	if( IsMouseInDVIwindow(g_winData.dviwin, &pt) )
	{
		RECT deskrc;
		int lptx, lpty;

		if(b_presentation_mode && (g_winData.dviwin.cover_sheet.fButton & CS_RBUTTON)){
			DownPage();
			return;
		}
		if(f_rectcut && g_winData.dviwin.pDib && (keyFlags & MK_SHIFT)){
			RECT rc;
			pt = GetDVICoordFromClient(&g_winData.dviwin, x, y);
			if(b_presentation_mode){
				if(keyFlags & MK_CONTROL){
					SetPoint(pt.x, pt.y, 0x81);
				}else{
					GetLastPoint(&lptx, &lpty);
					SetPoint(pt.x, pt.y, 1);
					pt = GetClientCoordFromDVI(&g_winData.dviwin, lptx, lpty);
					rc.left = pt.x;
					rc.right = x;
					if(rc.left > rc.right){
						lptx = rc.left;
						rc.left = rc.right;
						rc.right = lptx;
					}
					if(rc.left > 3)
						rc.left -=4;
					else
						rc.left = 0;
					rc.right+=4;
					rc.top = pt.y;
					rc.bottom = y;
					if(rc.top > rc.bottom){
						lpty = rc.top;
						rc.top = rc.bottom;
						rc.bottom = lpty;
					}
					if(rc.top > 3)
						rc.top -= 4;
					else
						rc.top = 0;
					rc.bottom += 4;
					p_s_invalid_rect = &rc;
				} /* if(keyFlags & MK_CONTROL) */
			} else if(pt.x >= rectcut.left){ /* b_presentation_mode */
				rectcut.right = pt.x;
				rectcut.bottom = pt.y;
			}
			ShowDVI(NULL, NULL);
			return;
		}
		
		if( !g_winData.dviwin.bCapture ){
			SetCapture( g_winData.dviwin.hWnd );
			g_winData.dviwin.bCapture = TRUE;
		}
		if(IS_MPAGE){
lbutton16:
			SelectPage( pt.x, pt.y );
			return;
		}
		
		if(f_rpcolor == 5){
			ShowMessage("Loupe is not supported in patch2 mode.",
				"Error", SM_OKCONT);
			return;
		}
		
		if((keyFlags & MK_CONTROL)){
			g_winData.dviwin.loupe.ctrl_fShape = g_winData.dviwin.loupe.fShape;
			g_winData.dviwin.loupe.fShape &= ~F_LCIRCLE;
			g_winData.dviwin.loupe.ctrl_diam = g_winData.dviwin.loupe.diam;
			g_winData.dviwin.loupe.diam = g_winData.dviwin.loupe.CTRL_size_scale & 0xffff;
			g_winData.dviwin.loupe.ctrl_div = g_winData.dviwin.loupe.div;
			g_winData.dviwin.loupe.div = (g_winData.dviwin.loupe.CTRL_size_scale >> 16);
		}
		InitLoupeWindow();
		ClientToScreen( g_winData.dviwin.hWnd, &pt );
		mptx = pt.x;
		if( g_winData.dviwin.loupe.fShape & F_LCIRCLE ){
			SetLoupeCircle();
		} else{
			SetLoupeRect();
		}
	
		if(g_winData.dviwin.loupe.fShape & F_LEDGE){
			GetWindowRect(GetDesktopWindow(), (LPRECT)&deskrc);
			if (pt.x - (signed int)g_winData.dviwin.loupe.diam/2 < deskrc.left)
			  lptx = deskrc.left;
			else if (pt.x + g_winData.dviwin.loupe.diam/2 > deskrc.right)
			  lptx = deskrc.right - g_winData.dviwin.loupe.diam;
			else
			  lptx = pt.x - g_winData.dviwin.loupe.diam/2;
			if (pt.y - (signed int)g_winData.dviwin.loupe.diam/2 < deskrc.top)
			  lpty = deskrc.top;
			else if (pt.y + g_winData.dviwin.loupe.diam/2 > deskrc.bottom)
			  lpty = deskrc.bottom - g_winData.dviwin.loupe.diam;
			else
			  lpty = pt.y - g_winData.dviwin.loupe.diam/2;
		}else{
			lptx = pt.x - g_winData.dviwin.loupe.diam/2;
			lpty = pt.y - g_winData.dviwin.loupe.diam/2;
		}
		SetWindowPos( g_winData.dviwin.loupe.hWnd, HWND_TOPMOST, lptx, lpty,
			g_winData.dviwin.loupe.diam, g_winData.dviwin.loupe.diam, SWP_NOACTIVATE );
		ShowWindow( g_winData.dviwin.loupe.hWnd, SW_SHOWNOACTIVATE );
		if(g_winData.dviwin.loupe.bKillCursor){
			ChangeMouseCursor(CS_HIDE);
		}
		g_winData.dviwin.loupe.bShown = TRUE;
		g_winData.dviwin.bDragging = TRUE;
	}
	return;
}

void DVIWIN_OnRButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
{
	if( g_winData.dviwin.fCoverMoveDir ) return;
	if( g_winData.dviwin.loupe.bShown || g_winData.dviwin.bCapture ){
		ShowWindow( g_winData.dviwin.loupe.hWnd, SW_HIDE );
		g_winData.dviwin.loupe.bShown = FALSE;
		if(g_winData.dviwin.loupe.ctrl_diam){
			g_winData.dviwin.loupe.fShape = g_winData.dviwin.loupe.ctrl_fShape;
			g_winData.dviwin.loupe.diam = g_winData.dviwin.loupe.ctrl_diam;
			g_winData.dviwin.loupe.div = g_winData.dviwin.loupe.ctrl_div;
			g_winData.dviwin.loupe.ctrl_diam = 0;
			InitLoupeWindow();
			ReleaseCapture();
			g_winData.dviwin.bCapture = FALSE;
		}
	}
	g_winData.dviwin.bDragging = FALSE;
	return;
}

void DVIWIN_OnMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
{
	f_m_down = 1;
	return;
}

void DVIWIN_OnMButtonUp(HWND hwnd, int x, int y, UINT flags)
{
	f_m_down = 0;
	return;
}



BOOL DVIWIN_OnSetCursor(HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg)
{
	/* WM_SETTIMER is sent if the mouse causes the cursor to move within a window
	   and mouse input is NOT captured;
	   Note that when a loupe is shown, the cursor is captured so that
	   this message will not be sent.
	   Also note that the loupe is drawn by the DVIWIN, and (since it is captured)
	   the mouse message is sent to the DVIWIN window (not the loupe). */
	
	/* returning:
		DefWindowProc() passes it to the parent window before it proceeds.
		TRUE prevents the child window to process the message.
		FALSE continue to process it.
		codeHitTest: HTBORDER (Mouse cursor on the border of the window) etc.
		msg: id of mouse message?
	*/
	
	SetCursor( g_winData.pCursor[g_winData.dviwin.fCursorShape] );
/*
	if( g_winData.dviwin.loupe.bShown && g_winData.dviwin.loupe.bKillCursor ){
		SetCursor( g_winData.pCursor[CS_HIDE] );
		 return TRUE;
	}
*/
	return TRUE;
}

void DVIWIN_OnTimer(HWND hwnd, UINT id)
{
	POINT pt;
	switch(id){ /* Timer ID */
		case MOUSE_NO_MOVE: /* Mouse has not been moved over two seconds. */
			GetCursorPos(&pt);
			if(g_winData.hWndPresenMenu){
				GetWindowRect(g_winData.hWndPresenMenu, &pmenu);
				if(  pt.x >= pmenu.left && pt.x <= pmenu.right
				&& pt.y >= pmenu.top  && pt.y <= pmenu.bottom)
					return;
//				if(f_pmshow && (pmenu.left || pmenu.top) ){
//					ShowWindow(g_winData.hWndPresenMenu, SW_HIDE);
//					f_pmshow = FALSE;
//				}
			}
			if(  pt.x < timer_cursor_pt.x + CUR_STOP && timer_cursor_pt.x < pt.x + CUR_STOP
				&& pt.y < timer_cursor_pt.y + CUR_STOP && timer_cursor_pt.y < pt.y + CUR_STOP ){
				ShowCursorByMove(FALSE);
			}else{
				timer_cursor_pt.x = pt.x;
				timer_cursor_pt.y = pt.y;
			}
			break;
		default:
			break;
	}
	return;
}

void DVIWIN_OnSysKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags)
{
	if(vk >= VK_F1 && vk <= VK_F12){
		if( fDown ){
			/* TODO: Why post WM_KEYDOWN/UP to the frame window? */
			PostMessage( g_winData.hMainWnd, WM_KEYDOWN, (WPARAM)vk, MAKELPARAM((cRepeat), (flags)) );
		} else{
			PostMessage( g_winData.hMainWnd, WM_KEYDOWN, (WPARAM)vk, MAKELPARAM((cRepeat), (flags)) );
		}
	}
	/* We shoud forward the message to DefWindowProc not to ignore the special,
		especially Alt+F4, key stroke. */
	if( fDown ){
		FORWARD_WM_SYSKEYDOWN(hwnd, vk, cRepeat, flags, DefWindowProc);
	} else{
		FORWARD_WM_SYSKEYUP(hwnd, vk, cRepeat, flags, DefWindowProc);
	}
	return;
}

void DVIWIN_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags)
{
	/* vk (wParam): virtual-key code of non-system key like VK_LBUTTON, VK_CANCEL (Ctrl+Break), etc.
		flags (HIWORD(lParam)): extended flags */
	UINT id_value;

	if( fDown ){
		BOOL bShiftDown = (HIBYTE(GetKeyState(VK_SHIFT)))?TRUE:FALSE;
		BOOL bCtrlDown  = (HIBYTE(GetKeyState(VK_CONTROL)))?TRUE:FALSE;
		int mult = 1;
		mult *= (bShiftDown)?5:1;
		mult *= (bCtrlDown)?10:1;
		switch( vk ){
			case VK_BACK:
				UpPage();
				return;
			case VK_SPACE:
				DownPage();
				return;

			case VK_NEXT: // Page DOWN Key
				if( b_presentation_mode ){
					DownPage();
					return;
				}
				TurnPage(mult);
				return;
			case VK_PRIOR: // PageUp Key
				if( b_presentation_mode ){
					UpPage();
				}
				TurnPage(-mult);
				return;
			case VK_HOME:
				if( bCtrlDown )	SendMessage( hwnd, WM_COMMAND, MAKEWPARAM(ID_TOPPAGE,0), 0 );
				else SendMessage( hwnd, WM_VSCROLL, MAKEWPARAM(SB_TOP, 0), (LPARAM)NULL );
				return;
			case VK_END:
				if( bCtrlDown )	SendMessage( hwnd, WM_COMMAND, MAKEWPARAM(ID_LASTPAGE,0), 0 );
				else SendMessage( hwnd, WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), (LPARAM)NULL );
				return;
			case VK_LEFT:
				if( bCtrlDown && bShiftDown ){
					OX -= 0x8000;
					ReSetMetric();
					ReOpen(TRUE);
					return;
				}
				if( g_winData.dviwin.nHscrollMax == 0 ){
					TurnPage(-1);
					return;
				}
				SendMessage( hwnd, WM_HSCROLL, MAKEWPARAM(SB_LINEUP,0), 0 );
				return;
			case VK_UP:
				if( bShiftDown && bCtrlDown ){
					OY -= 0x8000;
					ReSetMetric();
					ReOpen(TRUE);
					return;
				}
				if( g_winData.dviwin.nVscrollMax == 0 ){
					UpPage();
					return;
				} else if( g_winData.dviwin.nVscrollPos == 0 ){
					if( !(flags & 0x4000) ) // the key is NOT hold to be pressed.
						UpPage();
					return;
				}
				SendMessage( hwnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP,0), 0 );
				return;
			case VK_RIGHT:
				if( bCtrlDown && bShiftDown ){
					OX += 0x8000;
					ReSetMetric();
					ReOpen(TRUE);
					return;
				}
				if( g_winData.dviwin.nHscrollMax == 0 ){
					TurnPage(1);
					return;
				}
				SendMessage( hwnd, WM_HSCROLL, MAKEWPARAM(SB_LINEDOWN,0), (LPARAM)NULL );
				return;
			case VK_DOWN:
				if( bShiftDown ){
					if( bCtrlDown ){
						OY += 0x8000;
						ReSetMetric();
						ReOpen(TRUE);
						return;
					}
					DownPage();
					return;
				}
				if( g_winData.dviwin.nVscrollMax == 0 ){
					DownPage();
					return;
				} else if( g_winData.dviwin.nVscrollPos == g_winData.dviwin.nVscrollMax ){
					if( !(flags & 0x4000) ) // the key is NOT hold to be pressed.
						DownPage();
				}
				SendMessage( hwnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN,0), (LPARAM)NULL );
				return;
			case VK_TAB:
				if( g_winData.info.hWnd )
					SetFocus( g_winData.info.hWnd );
				if( g_winData.hWndPick )
					SetFocus( g_winData.hWndPick );
				return;
			case VK_DELETE:
				if(b_presentation_mode){
					SetPoint(0, 0, -2);
					ShowDVI(NULL, NULL);
					return;
/*
					id_value = ID_DRERACE;
					goto wmcmd;
*/				
				}
				break;
			case VK_RETURN:
				if( g_winData.info.hWnd )
					SendMessage( hwnd, WM_COMMAND, ID_HIS_CANCEL, 0 );
				if( g_winData.hWndPick )
					SendMessage( g_winData.hWndPick, WM_COMMAND, ID_HIS_CANCEL, 0 );
				break;

			default:
				if(VK_F1 <= vk && vk <= VK_F12){
					if(b_presentation_mode){
						// pos = GetKeyState(VK_SHIFT);
						switch(vk){
							case VK_F1:
								if(bShiftDown){
									if((id_value = key_trans[key_table[vk + (0x80 + 12 - VK_F1)]].id) != 0 )
										SendMessage( hwnd, WM_COMMAND, MAKEWPARAM(id_value,0), 0 );
								}
								ShowWinHelp(IDH_PRESENKEY);
								return;
/*
							case VK_F4:
								id_value = ID_RECTON;
								break;
*/
							case VK_F5:
								id_value = (bShiftDown)?ID_DRRED:ID_COVERON;
								break;
							case VK_F6:
								id_value = (bShiftDown)?ID_DRBLACK:ID_COVEROFF;
								break;
							case VK_F7:
								id_value = (bShiftDown)?ID_DRBLUE:ID_COVERSUSPEND;
								break;
							case VK_F8:
								id_value = (bShiftDown)?ID_DRGREEN:ID_COVERRETURN;
								break;
							case VK_F9:
								id_value = (bShiftDown)?ID_DTHICK:ID_COVERSHEET;
								break;
/*
							case VK_F10:			// this doesn't work??
								id_value = ID_DRLINE;
								break;
*/
							case VK_F11:
								id_value = (bShiftDown)?ID_DRBOX:ID_DRLINE;
								break;
							case VK_F12:
								id_value = (bShiftDown)?ID_SHAPE:ID_RECTON;
								break;
							default:
								if((id_value = key_trans[key_table[vk + ((bShiftDown)?(0x80 + 12 - VK_F1):(0x80 - VK_F1))]].id) != 0 )
									SendMessage( hwnd, WM_COMMAND, MAKEWPARAM(id_value,0), 0 );
								break;
						}
						SendMessage( hwnd, WM_COMMAND, MAKEWPARAM(id_value,0), 0 );
						return;
					} /* b_presentation_mode */
					if((id_value = key_trans[key_table[vk + ((bShiftDown)?(0x80 + 12 - VK_F1):(0x80 - VK_F1))]].id) != 0 ){
						SendMessage( hwnd, WM_COMMAND, MAKEWPARAM(id_value,0), 0 );
						return;
					}
				} /* Function Keys */
		} /* switch(vk) */
		return;
	} /* if(fDown) */
}

void DVIWIN_OnSysCommand(HWND hwnd, UINT cmd, int x, int y)
{
	// cmd &= 0xfff0;
	switch( cmd & 0xfff0 ){
		case SC_CLOSE:
			SendMessage( g_winData.hMainWnd, WM_CLOSE, 0, 0 );
			return;
		default:
			break;
	}
	FORWARD_WM_SYSCOMMAND(hwnd,cmd,x,y,DefWindowProc);
}


void SetPageView( int currentpage )
{
	char temp[17];

	if(GetTotalPage()){
		SetDlgItemInt( g_winData.toolbar.hWndToolBar, ID_PAGEEDIT, 
			currentpage, FALSE );
		wsprintf( temp, "(%d)", TransPage( currentpage) );
		SetWindowText( g_winData.toolbar.hWndNombreStatic, temp );
	}
}

void SetUpSearchFromCombo( LPFINDREPLACE find_replace )
{
	char szTemp[MAX_FIND_LEN+1];
	HWND hwnd;
	
	/* This function setup a string to search buffer from combo box.
	   For this, if edit box in combobox doesn't have a keyboard focus
	   this function need to be nothing, else we remove it
	   from combobox and set it to DVI window. One more we have to do is
	   to remove list box if it was shown.
	   I believe that drop down list box is shown only if edit box 
	   or the combo box has keyboard focus.
	   If my think is a lie, please tell me. */
	hwnd = GetFocus();
	if( hwnd == g_winData.toolbar.hWndEditInCombo
	 || hwnd == g_winData.toolbar.hWndFindCombo )
	{
		SetFocus( g_winData.dviwin.hWnd );
	}
	szTemp[0] = 0;
	SendMessage( g_winData.toolbar.hWndFindCombo, CB_SHOWDROPDOWN, FALSE, 0 );
	/* the following will be proceeded when edit box in combo box will have
	   had keyboard focus. Only we have to do is to copy the string at
	   edit box in combo box to our buffer to finding string. */
	GetWindowText( g_winData.toolbar.hWndFindCombo, szTemp, MAX_FIND_LEN );
	if(szTemp[0])
		strcpy( szFind, szTemp );
	SetSearchStr( (unsigned char*)szFind );
	AddStringToCombo( szFind );
	SetStringToCombo( szFind );
}

static BOOL IsMouseInDVIwindow( const DVI_WINDOW_PROPERTY w, POINT* p_pt )
{
	/* 2012/02/12 Change the specification.
	   Only return TRUE if the mouse cursor is INSIDE the client area.
	   Note that, if the loupe is shown (DVIWIN is hidden by another),
	   WindowFromPoint could not return the DVIWIN. */
//	HWND hWnd;
	GetCursorPos( p_pt );
/*
	if( w.hWnd != (hWnd = WindowFromPoint(*p_pt)) ){ // e.g., the cursor is on the scroll bar
		ScreenToClient( w.hWnd, p_pt );
		return FALSE;
	}
*/
//	if( w.hWnd == WindowFromPoint(*p_pt) ) return TRUE;
	ScreenToClient( w.hWnd, p_pt );
	if( 0 <= p_pt->y && p_pt->y <= w.cyClient
	 && 0 <= p_pt->x && p_pt->x <= w.cxClient ) return TRUE;
	return FALSE;
}

static void SetPageMoveButtons( DVI_WINDOW_PROPERTY* w )
{
	HWND hwnd = g_winData.toolbar.hWndToolBar;
	
	WPARAM top = f_rev_movebutton?ID_LASTPAGE:ID_TOPPAGE;
	WPARAM last = f_rev_movebutton?ID_TOPPAGE:ID_LASTPAGE;
	WPARAM prev = f_rev_movebutton?ID_NEXTPAGE:ID_PREVPAGE;
	WPARAM next = f_rev_movebutton?ID_PREVPAGE:ID_NEXTPAGE;

	if( w->pDib == NULL || GetTotalPage() == 1 )
	{
		SendMessage( hwnd, TB_ENABLEBUTTON, top, MAKELONG(FALSE,0) );
		SendMessage( hwnd, TB_ENABLEBUTTON, prev, MAKELONG(FALSE,0) );
		SendMessage( hwnd, TB_ENABLEBUTTON, next, MAKELONG(FALSE,0) );
		SendMessage( hwnd, TB_ENABLEBUTTON, last, MAKELONG(FALSE,0) );
		EnableMenuItem( g_winData.hMenu, ID_TOPPAGE, MF_GRAYED );
		EnableMenuItem( g_winData.hMenu, ID_PREVPAGE, MF_GRAYED );
		EnableMenuItem( g_winData.hMenu, ID_UPPAGE, MF_GRAYED );
		EnableMenuItem( g_winData.hMenu, ID_NEXTPAGE, MF_GRAYED );
		EnableMenuItem( g_winData.hMenu, ID_DOWNPAGE, MF_GRAYED );
		EnableMenuItem( g_winData.hMenu, ID_LASTPAGE, MF_GRAYED );
		return;
	}
	SendMessage( hwnd, TB_ENABLEBUTTON, top, MAKELONG(TRUE,0) );
	SendMessage( hwnd, TB_ENABLEBUTTON, prev, MAKELONG(TRUE,0) );
	SendMessage( hwnd, TB_ENABLEBUTTON, next, MAKELONG(TRUE,0) );
	SendMessage( hwnd, TB_ENABLEBUTTON, last, MAKELONG(TRUE,0) );
	EnableMenuItem( g_winData.hMenu, ID_TOPPAGE, MF_ENABLED );
	EnableMenuItem( g_winData.hMenu, ID_PREVPAGE, MF_ENABLED );
	EnableMenuItem( g_winData.hMenu, ID_UPPAGE, MF_ENABLED );
	EnableMenuItem( g_winData.hMenu, ID_NEXTPAGE, MF_ENABLED );
	EnableMenuItem( g_winData.hMenu, ID_DOWNPAGE, MF_ENABLED );
	EnableMenuItem( g_winData.hMenu, ID_LASTPAGE, MF_ENABLED );
	/* assume GetTotalPage() > 1 */
	if( GetCurrentPage() == 1 )
	{
		SendMessage( hwnd, TB_ENABLEBUTTON, top, MAKELONG(FALSE,0) );
		SendMessage( hwnd, TB_ENABLEBUTTON, prev, MAKELONG(FALSE,0) );
		EnableMenuItem( g_winData.hMenu, ID_TOPPAGE, MF_GRAYED );
		EnableMenuItem( g_winData.hMenu, ID_PREVPAGE, MF_GRAYED );
		EnableMenuItem( g_winData.hMenu, ID_UPPAGE, MF_GRAYED );
	}
	if( GetCurrentPage() == GetTotalPage() )
	{
		SendMessage( hwnd, TB_ENABLEBUTTON, next, MAKELONG(FALSE,0) );
		SendMessage( hwnd, TB_ENABLEBUTTON, last, MAKELONG(FALSE,0) );
		EnableMenuItem( g_winData.hMenu, ID_NEXTPAGE, MF_GRAYED );
		EnableMenuItem( g_winData.hMenu, ID_DOWNPAGE, MF_GRAYED );
		EnableMenuItem( g_winData.hMenu, ID_LASTPAGE, MF_GRAYED );
	}
	if( f_2page & F_MPAGE ) // 4 or 16 pages
	{
		SendMessage( hwnd, TB_ENABLEBUTTON, top, MAKELONG(FALSE,0) );
		SendMessage( hwnd, TB_ENABLEBUTTON, last, MAKELONG(FALSE,0) );
		EnableMenuItem( g_winData.hMenu, ID_TOPPAGE, MF_GRAYED );
		EnableMenuItem( g_winData.hMenu, ID_LASTPAGE, MF_GRAYED );
	}
}

void InitMenuItems( void )
{
	int item_id, i;
	char* tmpname;
	HMENU hmenu;
	
	tmpname = GetParaString("y");
	hmenu = GetSubMenu(g_winData.hMenu, 6);
	CheckMenuItem(hmenu, 0, MF_BYPOSITION|MFS_UNCHECKED);
	CheckMenuItem(hmenu, 1, MF_BYPOSITION|MFS_UNCHECKED);
	CheckMenuItem(hmenu, 2, MF_BYPOSITION|MFS_UNCHECKED);
	CheckMenuItem(hmenu, 7, MF_BYPOSITION|MFS_UNCHECKED);

	if(tmpname != NULL && *tmpname){
		switch( toupper(*tmpname) )
		{
			case 'A':
				switch( tmpname[1] )
				{
					case '3':
						item_id = ID_PAPER_A3;
						break;
					case '4':
						item_id = ID_PAPER_A4;
						break;
					case '5':
						item_id = ID_PAPER_A5;
						break;
					case '6':
						item_id = ID_PAPER_A6;
						break;
					case '7':
						item_id = ID_PAPER_A7;
						break;
				}
				break;
			case 'E':
				switch( tmpname[1] )
				{
					case '3':
						item_id = ID_PAPER_B3;
						break;
					case '4':
						item_id = ID_PAPER_B4;
						break;
					case '5':
						item_id = ID_PAPER_B5;
						break;
					case '6':
						item_id = ID_PAPER_B6;
						break;
					case 'x':
						item_id = ID_PAPER_EXECUTIVE;
						break;
				}
				break;
			case 'B':
				switch( tmpname[1] )
				{
					case '3':
						item_id = ID_PAPER_B3JPN;
						break;
					case '4':
						item_id = ID_PAPER_B4JPN;
						break;
					case '5':
						item_id = ID_PAPER_B5JPN;
						break;
					case '6':
						item_id = ID_PAPER_B6JPN;
						break;
				}
				break;
			case 'J':
				switch( tmpname[1] )
				{
					case '1':
						item_id = ID_PAPER_KIKU;
						break;
					case '2':
						item_id = ID_PAPER_46;
						break;
					case '3':
						item_id = ID_PAPER_NEWBOOK;
						break;
					case '4':
						item_id = ID_PAPER_AB;
						break;
				}
				break;
			case 'L':
				switch( tmpname[2] )
				{
					case 't':
						item_id = ID_PAPER_LETTER;
						break;
					case 'g':
						item_id = ID_PAPER_LEGAL;
						break;
				}
				break;
			case 'G':
				switch( tmpname[5] )
				{
					case 't':
						item_id = ID_PAPER_GOVLETTER;
						break;
					case 'g':
						item_id = ID_PAPER_GOVLEGAL;
						break;
				}
				break;
			case 'H':
				if( tmpname[1] == 'a' )
					item_id = ID_PAPER_HALFLETTER;
				else
					item_id = ID_PAPER_POSTCARD;
				break;
			case 'S':
				item_id = (tmpname[1] == 'V')?
						ID_PAPER_SVGA:ID_PAPER_SXGA;
				break;
			case 'X':
				item_id = ID_PAPER_XGA;
				break;
			case 'U':
				item_id = ID_PAPER_UVGA;
				break;
			case 'F':
				item_id = ID_PAPER_USERDEFINED;
				break;
		}	
		tmpname += strlen(tmpname)-1;
		CheckMenu( ID_LANDSCAPE, (*tmpname == 'L')?TRUE:FALSE );
	}
	else{
		item_id = ID_PAPER_A4;
		CheckMenu(ID_LANDSCAPE, FALSE);
	}
	if(item_id >= ID_PAPER_A3 && item_id <= ID_PAPER_B6JPN){
		if(item_id <= ID_PAPER_A7)
			CheckMenuItem(hmenu, 0, MF_BYPOSITION|MFS_CHECKED);
		else if(item_id <= ID_PAPER_B6)
			CheckMenuItem(hmenu, 1, MF_BYPOSITION|MFS_CHECKED);
		else
			CheckMenuItem(hmenu, 2, MF_BYPOSITION|MFS_CHECKED);
	}else{
		switch(item_id){
			case ID_PAPER_46:
			case ID_PAPER_KIKU:
			case ID_PAPER_NEWBOOK:
			case ID_PAPER_AB:
			case ID_PAPER_HALFLETTER:
			case ID_PAPER_GOVLEGAL:
			case ID_PAPER_GOVLETTER:
			case ID_PAPER_SVGA:
			case ID_PAPER_XGA:
			case ID_PAPER_SXGA:
			case ID_PAPER_UVGA:
				CheckMenuItem(hmenu, 7, MF_BYPOSITION|MFS_CHECKED);
		}
	}
	for(i = ID_PAPER_A3; i <= ID_PAPER_USERDEFINED ; i++)
		CheckMenu(i, 0);
	CheckMenuSet(item_id, item_id, item_id);
}

void AutoSaveBmp( void )
{
	static BOOL f_twice = FALSE;
	char save_filename[MAX_PATH];
	FILE* fp;
	int i, j, k;
	int col = 0;

	if( !autosavebmp.f_autosavebmp || g_winData.dviwin.pDib == NULL ) return;
	if( autosavebmp.f_bmp == 1 && f_twice )
	{
		f_twice = FALSE;
		return;
	}

	j = 0;
	for( i = 0; autosavebmp.sz_template[i] != '\0'; i++ )
	{
		if( j == MAX_PATH - 6 ) break;
		if( autosavebmp.sz_template[i] != '^' )
		{
			save_filename[j++] = autosavebmp.sz_template[i];
			continue;
		}
		else
		{
			col = 0;
expand_macro:
			if( '0' <= autosavebmp.sz_template[++i] && autosavebmp.sz_template[i] <= '9' )
			{
				col = autosavebmp.sz_template[i] - '1' + 1;
				goto expand_macro;
			}
			else
			{
				switch( autosavebmp.sz_template[i] )
				{
					case 'd':
						if( col == 0 )
						{
							char temp[10];
							wsprintf( temp, "%lu", GetCurrentPage() );
							for( k = 0; temp[k] != '\0'; k++ )
							{
								save_filename[j++] = temp[k];
								if( j == MAX_PATH - 6 ) break;
							}
						}
						else
						{
							char exp_str[6];
							char temp[10];
							wsprintf( exp_str, "%%0%dlu", col );
							wsprintf( temp, exp_str, GetCurrentPage() );
							for( k = 0; temp[k] != '\0'; k++ )
							{
								save_filename[j++] = temp[k];
								if( j == MAX_PATH - 6 ) break;
							}
						}
						break;
					case 'f':
						for( k = 0; current_name_pt[k] != '\0'; k++ )
						{
							save_filename[j++] = current_name_pt[k];
							if( j == MAX_PATH - 6 ) break;
						}
						j -= 4;
						break;
				} // end '^f' or '^d'
			} // end '^'
		} // end replace
	} // end
	save_filename[j] = '\0';
	ToDviDir();
	switch( autosavebmp.f_bmp )
	{
		case 0: // BMP
			strcat( save_filename, ".bmp" );
			fp = fopenf( save_filename, "wb");
			if( fp == NULL ) return;
			fwrite( (char*)g_winData.dviwin.pDib - sizeof(BITMAPFILEHEADER),
				((BITMAPFILEHEADER *)
					((char*)g_winData.dviwin.pDib-sizeof(BITMAPFILEHEADER)))->bfSize, 1, fp);
			fclose(fp);
			break;
		case 1:	// EMF
			strcat( save_filename, ".emf" );
			f_twice = TRUE;
			Page2EMF( save_filename );
			SendMessage( g_winData.hMainWnd, WM_COMMAND, ID_REOPEN, 0 );
			break;
		case 2: // BMC
			strcat( save_filename, ".bmc");
			bmp2bmc(save_filename,
				(unsigned char*)g_winData.dviwin.pDib - sizeof(BITMAPFILEHEADER),
				((BITMAPFILEHEADER *)((char*)g_winData.dviwin.pDib-sizeof(BITMAPFILEHEADER)))->bfSize);
			break;
		default:
			break;
	}
	return;
}

void AnimationPointer( DVI_WINDOW_PROPERTY *w, HWND hWndParent, HINSTANCE
		hInst, int x, int y, BOOL fDraw )
{
	char anim[] = "AnimPoint";
	UINT anim_wnd_id = 40000;

	WNDCLASSEX wc;
	HWND hwnd;
	static POINT pt;
	HDC hdc;
	int center = 15;
	int i;
	HBRUSH hBrush, hOldBrush;

	if( !fDraw && f_animecursor){
		pt = GetClientCoordFromDVI(w, x, y);
//		pt.y -= 2*center;
		pt.x -= center;
		pt.y -= center;
		f_DrawAnimationPointer = TRUE;
		return;
	}
	if( !f_DrawAnimationPointer )
		return;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = DefWindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = NULL;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	// wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	/* 2012/01/12 Make sure the class cursor should be NULL. */
	wc.hCursor = NULL;
	wc.hbrBackground = GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = anim;
	wc.hIconSm = NULL;
	RegisterClassEx( &wc );

	hwnd = CreateWindowEx( WS_EX_TRANSPARENT, anim, anim, WS_CHILD | WS_VISIBLE,
		pt.x, pt.y, 2*center, 2*center, hWndParent, (HMENU)anim_wnd_id, 
		hInst, NULL );
	ShowWindow( hwnd, SW_SHOWNORMAL );
	UpdateWindow( hwnd ); // Send WM_PAINT
	hdc = GetDC(hwnd);
	hBrush = CreateSolidBrush(RGB(0xff,0x00,0x00));
	hOldBrush = SelectObject(hdc,hBrush);
	for( i = 1; i < center; i+=4 ){
		Ellipse( hdc, center-i, center-i, center+i, center+i );
		Sleep(1);
	}
	SelectObject(hdc,hOldBrush);
	DeleteObject(hBrush);
	hBrush = GetStockObject(WHITE_BRUSH);
	SelectObject(hdc, hBrush);
	for( i = 1; i < center; i+=2 ){
		Ellipse( hdc, center-i, center-i, center+i, center+i );
		Sleep(1);
	}
	Sleep( 0 );
	ReleaseDC(hwnd, hdc);
	DestroyWindow( hwnd );
	f_DrawAnimationPointer = FALSE;
	return;
}

int ChangeMouseCursor( CURSOR_SHAPE s )
{
	static CURSOR_SHAPE prev = CS_NORMAL;
	CURSOR_SHAPE cs;

	if( g_winData.dviwin.fCursorShape == s ) return 0;
	switch( s ){
		case CS_HIDE:
			g_winData.dviwin.fCursorShape = s;
			g_winData.dviwin.bCursorShown = FALSE;
			break;
		case CS_WAIT:
			g_winData.dviwin.fCursorShape = s;
			g_winData.dviwin.bCursorShown = FALSE;
			break;
		case CS_PREV:
			cs = prev;
			if( g_winData.dviwin.fCursorShape != CS_HIDE && g_winData.dviwin.fCursorShape != CS_WAIT ){
				prev = g_winData.dviwin.fCursorShape;
			}
			g_winData.dviwin.fCursorShape = cs;
			g_winData.dviwin.bCursorShown = TRUE;
			break;
		default:
			if( g_winData.dviwin.fCursorShape != CS_HIDE && g_winData.dviwin.fCursorShape != CS_WAIT ){
				prev = g_winData.dviwin.fCursorShape;
			}
			g_winData.dviwin.fCursorShape = s;
			g_winData.dviwin.bCursorShown = TRUE;
			break;
	}
	return (int)SetCursor( g_winData.pCursor[g_winData.dviwin.fCursorShape] );
}

int DownPage( void )
{
	int xx, yy;
	int pos;
	RECT rcStop;

	if(g_winData.dviwin.pDib == NULL) return 0;
	if(b_presentation_mode && (g_winData.dviwin.cover_sheet.fOn == CS_ON) && !f_2page){
		if(GetPause(&xx, &yy, 1) >= 0){
			MoveCover(xx, yy, 1);
			if(g_winData.dviwin.cover_sheet.bScrollToPause)
				ScrollToDVIposition(&g_winData.dviwin, GetCoverPos().x, GetCoverPos().y, g_winData.dviwin.cover_sheet.fPlace);
			return 0;
		}
		if( GetCoverPos().x < GetTextXSize() && GetCoverPos().y < GetTextYSize() ){
			MoveCover((g_winData.dviwin.cover_sheet.fPlace & CS_RIGHT)?0x2000:-0x2000, 0x10000, 0);
			if(g_winData.dviwin.cover_sheet.bScrollToPause)
				ScrollToDVIposition(&g_winData.dviwin, GetCoverPos().x, GetCoverPos().y, g_winData.dviwin.cover_sheet.fPlace);
			return 0;
		}
	}
	
	if(!IS_MPAGE && CheckStop(0)){
		SetStartPage(GetCurrentPage());
		f_KeepDraw = TRUE;
		if(pDibKeep) FreeBmp(pDibKeep);
		if(f_pDibKeep){
			pDibKeep = g_winData.dviwin.pDib;
			g_winData.dviwin.pDib = NULL;
		}
		rcStop.left = rcStop.right = 0;
		JoinBoundigBox(&rcStop, &StopG1Rec);
		SendMessage( g_winData.hMainWnd, WM_USER_FILE_OPEN, 0, 0 );
	}
	if(GetCurrentPage() >= GetTotalPage()){
		if( b_presentation_mode ){
//			temp_page = -50000;
//			goto nxtpg;
			return ShowNewPage(-GetTotalPage());
		} else
			return 0;
	}
	SaveH_Hist(&g_winData.dviwin, 1);
	if(IS_MPAGE){
		if(GetCurrentPage() >= GetTotalPage()) return 0;
		pos = GetCurrentPage() + 1;
		xx = f_2page;
		if(ReplaceBmp(&g_winData.dviwin, GotoPage(pos)) == FALSE) return 0;
		if(xx & 0x2000) return Show16Pages();
		return Show4Pages();
	}	
	if(ReplaceBmp(&g_winData.dviwin, nextpage(GetShiftPage(1))) == FALSE) return 0;
	ScrollWindow( g_winData.dviwin.hWnd, 0, -g_winData.dviwin.nVscrollPos, NULL, NULL );
	g_winData.dviwin.cover_sheet.bArrangeForPause = TRUE;
	if( f_flatscroll && GetVersionLevel() > 0 ){
		g_FlatSB_SetScrollPos( g_winData.dviwin.hWnd, SB_VERT, g_winData.dviwin.nVscrollPos = 0, TRUE );
	} else{
		SetScrollPos( g_winData.dviwin.hWnd, SB_VERT, g_winData.dviwin.nVscrollPos = 0, TRUE );
	}
	return ShowDVI0(&rcStop);
}

int UpPage( void ) /* uppage */
{
	if(g_winData.dviwin.pDib == NULL || GetCurrentPage() <= 1) return 0;
	SaveH_Hist(&g_winData.dviwin, 1);
	if(IS_MPAGE){
		int pos, xx;
		if(f_2top <= 1) return 0;
		pos = f_2top - (IS_16PAGE?16:4);
		xx = f_2page;
		if(ReplaceBmp(&g_winData.dviwin, GotoPage(pos)) == FALSE) return 0;
		if(xx & 0x2000) return Show16Pages();
		else Show4Pages();
	}
	if(ReplaceBmp(&g_winData.dviwin, nextpage(GetShiftPage(-1))) == FALSE) return 0;
	ScrollWindow( g_winData.dviwin.hWnd, 0, 
		g_winData.dviwin.nVscrollMax - g_winData.dviwin.nVscrollPos, NULL, NULL );
	if( f_flatscroll && GetVersionLevel() > 0 ){
		g_FlatSB_SetScrollPos( g_winData.dviwin.hWnd, SB_VERT,
			g_winData.dviwin.nVscrollPos = g_winData.dviwin.nVscrollMax, TRUE );
	} else{
		SetScrollPos( g_winData.dviwin.hWnd, SB_VERT,
			g_winData.dviwin.nVscrollPos = g_winData.dviwin.nVscrollMax, TRUE );
	}
	return ShowDVI0( NULL );
}

int TurnPage( int nTurn )
{
	if(g_winData.dviwin.pDib == NULL) return 0;
	return ShowNewPage( nTurn );
}

int ShowNewPage( int nSkip ) // nxtpg
{
	int xx;
	int pos;
	BYTE* pDibNew;

	CoverSuspend();
	SaveH_Hist(&g_winData.dviwin, 1);
	SetPageMoveButtons( &g_winData.dviwin );

	if(IS_MPAGE){
		if(nSkip == 1){
			if(GetCurrentPage() >= GetTotalPage()) return 0;
			pos = GetCurrentPage() + 1;
		}else if(nSkip == -1){
			if(f_2top <= 1) return 0;
			pos = f_2top - (IS_16PAGE?16:4);
		}
		if( nSkip == 1 || nSkip == -1 ){
			xx = f_2page;
			if(ReplaceBmp(&g_winData.dviwin, GotoPage(pos)) == FALSE) return 0;
			if(xx & 0x2000) return Show16Pages();
			return Show4Pages();
		}
	}
	if((pDibNew	= nextpage(GetShiftPage(nSkip))) == NULL)
		return 0;
renew:
	return RenewDVI( &pDibNew, NULL );
}

BOOL JumpHistory( int page, int mode, POINT pt ) /* go_hist */
{

	if( page == 0 ){
		if(mode < 0){
			if(f_hist_pt > f_hist0 + 1){
				SendMessage(g_winData.dviwin.hWnd, WM_USER_HISTORY_OPEN, MAKEWPARAM(f_hist_pt - 2, TRUE), 0L);
				return TRUE;
			} else return FALSE;
		}
		else return FALSE;
	}
	if( page != GetCurrentPage()
	  && ReplaceBmp(&g_winData.dviwin, GotoPage(page)) == FALSE )
		return FALSE;
	SetScrollPosToMakePointInBufferCenterOfWindow(&g_winData.dviwin, pt.x, pt.y);
	ShowDVI(NULL, NULL);
	return TRUE;
}


int ShowDVI0( RECT* pRect ) // show0:
{
	if(IS_2PAGE){
		BYTE* pDibNew;
		pDibNew = g_winData.dviwin.pDib - sizeof(BITMAPFILEHEADER);
		return RenewDVI( &pDibNew, NULL );
	} else{
		return ShowDVI( pRect, NULL );
	}
}

int ShowDVI( RECT* pRect, const POINT* p_cursor_pt ) // show:
{
	/* if f_h_renew is TRUE, this function should move the cursor to the cursor_pt
		indicated by a dvi-coordinate. */
	/* pRect: a domain to be invalidate. */
	int temp_page;
	char szText[300];
	int xx, yy;
	int pos;

	if(!ArrangeScroll(&g_winData.dviwin, 0) &&
	   (!b_presentation_mode || g_winData.dviwin.cover_sheet.fOn != CS_ON || f_2page)){
		if(g_winData.dviwin.bHand){
			g_winData.dviwin.bHand = FALSE;
			ChangeMouseCursor(CS_NORMAL);
		}
	} else if(g_winData.dviwin.loupe.fShape & F_LHAND) g_winData.dviwin.bHand = TRUE;

	if(	f_h_renew == TRUE && p_cursor_pt != NULL ){
		/* pt should be in a dvi coordinate, but now in screen? */
		ShowAtCenterAndLocateCursor(&g_winData.dviwin, p_cursor_pt->x, p_cursor_pt->y);
		AnimationPointer( &g_winData.dviwin, g_winData.dviwin.hWnd, g_winData.hInstance, p_cursor_pt->x, p_cursor_pt->y, FALSE );
		f_h_renew = FALSE;
	}
	
	SetPageMoveButtons( &g_winData.dviwin );
	
	SendMessage( g_winData.toolbar.hWndToolBar, TB_CHECKBUTTON, ID_MHAND, MAKELONG((g_winData.dviwin.loupe.fShape & F_LHAND)?TRUE:FALSE,0) );
	
	if( g_winData.dviwin.bCapture ){
		ReleaseCapture();
		g_winData.dviwin.bCapture = FALSE;
	}
	
	if(g_winData.dviwin.cover_sheet.bArrangeForPause){
		if(b_presentation_mode && !f_2page && g_winData.dviwin.cover_sheet.bOnForPause){
			if(!GetPause(&xx, &yy, 2)){			// No special pause
				SetCoverPos( GetTextXSize(), GetTextYSize() );
			}else if(GetPause(&xx, &yy, 0) == 0){	// Initial use
				GetPause(&xx, &yy, 1);
				MoveCover(xx, yy, 1);
			}
		}
		g_winData.dviwin.cover_sheet.bArrangeForPause = FALSE;
	}
	temp_page = IsHyperTag();

	if(!(IS_2PAGE) || !pDib2 ){
		if(temp_page > 0)
			ShowBox(g_winData.dviwin.pDib, h_box + temp_page + 1, h_box[temp_page].y0, f_h_color);
	}
#if	HYPER_2VERT
	else if(IS_2VERT && b_presentation_mode){
		if(temp_page > 0)
			ShowBox(pDib2, h_box + temp_page + 1, h_box[temp_page].y0, f_h_color);
		pos = GetCurrentPage();
		ChgPage(pos - (IsSecondPage(pos)?1:(-1)));
		if(pos != GetCurrentPage() && (temp_page = IsHyperTag()) > 0)
			ShowBox(g_winData.dviwin.pDib, h_box + temp_page + 1, h_box[temp_page].y0, f_h_color);
		ChgPage(pos);
	}
#endif
	if(ChangeToolBar(-1)){
		if(!GetUserKey(3))
			SendMessage(g_winData.toolbar.hWndToolBar, TB_ENABLEBUTTON, 
				ID_BNEXTHIST, (h_hist_pt != h_hist_n));
		if(!GetUserKey(5))
			SendMessage(g_winData.toolbar.hWndToolBar, TB_ENABLEBUTTON, 
				ID_BGOMARK, (h_hist[PAGE_MARK].id == id_dvi));
	}

	/* Send a WM_PAINT! */
	if(!g_winData.dviwin.bStopRedrawByUser){
		if(pDibKeep){
			RECT rcc;
			RECT rcStop;
			memset( &rcc, 0, sizeof(RECT) );
			memset( &rcStop, 0, sizeof(RECT) );
			if( pRect == NULL ) pRect = &rcStop;
			JoinBoundigBox(pRect, &StopG0Rec);
			if(pRect->left < pRect->right){
				pRect->left  /= (xx = GetXGray());
				pRect->right = (pRect->right+xx-1)/xx;
				pRect->top   /= (yy = GetYGray());
				pRect->bottom = (pRect->bottom+yy-1)/yy;
			}
			xx = CompBMP(g_winData.dviwin.pDib, pDibKeep, &rcc);
			FreeBmp(pDibKeep);
			pDibKeep = NULL;
			if(xx >= 0){
				JoinBoundigBox(&rcc, pRect);
				rcc.left  += g_winData.dviwin.cxIndent- g_winData.dviwin.nHscrollPos;
				if(rcc.left < 0)
					rcc.left = 0;
				rcc.right += g_winData.dviwin.cxIndent- g_winData.dviwin.nHscrollPos;
				if(rcc.right < 0) 
					rcc.right = 0;
				rcc.top   += g_winData.dviwin.cyIndent- g_winData.dviwin.nVscrollPos;
				if(rcc.top < 0)
					rcc.top = 0;
				rcc.bottom += g_winData.dviwin.cyIndent- g_winData.dviwin.nVscrollPos;
				if(rcc.bottom < 0)
					rcc.bottom = 0;
				InvalidateRect( g_winData.dviwin.hWnd, &rcc, FALSE );
			}else
				InvalidateRect( g_winData.dviwin.hWnd, p_s_invalid_rect, TRUE );
		} /* if(pDibKeep) */ else{
			InvalidateRect( g_winData.dviwin.hWnd, p_s_invalid_rect, TRUE );
		}
		p_s_invalid_rect = NULL; 
		UpdateWindow( g_winData.dviwin.hWnd );
		AnimationPointer( &g_winData.dviwin, g_winData.dviwin.hWnd, g_winData.hInstance, 
			0, 0,TRUE );
	} // if(!g_winData.dviwin.bStopRedrawByUser)
	
	wsprintf( szText, "%s(%d/%d) - %s", 
		current_name,
		GetCurrentPage(),
		GetTotalPage(),
		g_winData.szWindowTitle );
	SetWindowText( g_winData.hMainWnd, szText );

	SetSpinRange( 1, GetTotalPage(), GetCurrentPage() );
	if( h_hist[RANGE_MARK].id == id_dvi )
		SetMarkRange( h_hist[PAGE_MARK].page,
			h_hist[RANGE_MARK].page);
	else
		SetMarkRange(0,0);
	SetPageView( SetStatusWindow() );
	UpdateWindow( g_winData.toolbar.hWndPageSpin );
	AutoSaveBmp();
	return 0;
}

int RenewDVI( BYTE** ppDibNew, const POINT* p_cursor_pt )
{
	if(IS_2PAGE) Get2Bmp();
	if(ReplaceBmp(&g_winData.dviwin, *ppDibNew) == FALSE){
		if( !(f_hyper & F_H_CURRENTPAGE) ) return 0;
	}
	f_hyper &= ~F_H_CURRENTPAGE;
	*ppDibNew = NULL;
	return ShowDVI(NULL, p_cursor_pt );
}

int SelectPage( int x, int y ) // lbutton16
{
	/* Select a page from 4/16 pages list shown on the window. */
	POINT pt;
	int size;
	int pos;
	BYTE *pDibNew;

	pt = GetDVICoordFromClient(&g_winData.dviwin, x, y);
	if(	 g_winData.dviwin.pDib == NULL
	  || pt.x < 0 || pt.x >= GetTextXSize()
	  || pt.y < 0 || pt.y >= GetTextYSize() ) return 0;
	size = (IS_16PAGE)?4:2;
	pos =  pt.y*size/GetTextYSize();
	pos =  f_2top + pos*size + pt.x*size/GetTextXSize();
	if(pos > GetTotalPage()) return 0;
	f_2page = 0;
	g_winData.dviwin.cover_sheet.bArrangeForPause = TRUE;
	AddKeepBMP(0);
	ClearKeepBMP();
	if( pos == GetCurrentPage() ) return ReOpen(FALSE);
	SaveH_Hist(&g_winData.dviwin, 1);
	pDibNew = GotoPage(pos);
	return RenewDVI( &pDibNew, &pt );
}

int Show16Pages( void ) // id_16page
{
	int pos;
	int t;

	if(!g_winData.dviwin.pDib) return 0;
	if( IS_MPAGE && IS_16PAGE ){
		pos = GetCurrentPage();
	} else{
		pos = GetTotalPage();
	}
	
	if( pos - GetCurrentPage() < 15){
		pos -= 15;
		t = f_dvioutspecial;
		f_dvioutspecial = FALSE;
		ReplaceBmp(&g_winData.dviwin, (BYTE*)GotoPage(pos));
		f_dvioutspecial = t;
	}
	if(!DisplayPages(4)) return 0;
	f_2page = F_MPAGE|F_16PAGE;
	return ShowDVI(NULL, NULL);
}

int Show4Pages( void ) // id_cross
{
	int pos;
	int xx;
	if(!g_winData.dviwin.pDib) return 0;
	if( IS_MPAGE && !IS_16PAGE ){
		pos = GetCurrentPage();
		goto page4;
	}
	if((pos = GetTotalPage()) - GetCurrentPage() < 3){
page4:	pos -= 3;
		xx = f_dvioutspecial;
		f_dvioutspecial = FALSE;
		ReplaceBmp(&g_winData.dviwin, GotoPage(pos));
		f_dvioutspecial = xx;
	}
	if(!DisplayPages(2)) return 0;
	f_2page = F_MPAGE;
	return ShowDVI(NULL,NULL);
}

int ReOpen( BOOL bCheckDib ) // re_open (FALSE), chk_re_open (TRUE)
{
	if( bCheckDib && g_winData.dviwin.pDib == NULL ) return NULL;
	SetStartPage(GetCurrentPage());
	return NewOpen();
}

int NewOpen( void ) // new_open
{
	int bg_color;
	int pos;
	if(b_presentation_mode && f_background == 2){
		bg_color = GetBackGround();
		if(pr_color != (COLORREF)bg_color){
			pr_color = (COLORREF)bg_color;
			pos = COLOR_APPWORKSPACE;
			SetSysColors(1, &pos, &pr_color);
		}
	}
	if(f_macro)
		SendMessage( g_winData.hMainWnd, WM_USER_FILE_OPEN, 0, 0 );
	else
		PostMessage( g_winData.hMainWnd, WM_USER_FILE_OPEN, 0, 0 );
	return 0;
}

static BOOL GetHyperReference( char* href )
{
	int ctrl_down;
	int pos;

	ctrl_down = HIBYTE(GetKeyState(VK_CONTROL));
	if((ctrl_down && !f_Din) || (!ctrl_down && f_Din)){
	if(!strncmp(href, "dviout:", 7) ){
		for(pos = 7; href[pos] == ' ' ; pos++);
		if( !strncmp(href+pos, "`in", 3) )
			return TRUE;
		}
	}
	if(ctrl_down && !f_Din && MessageCBox(g_winData.hMainWnd, 
			"Execute the above Hyper Jump", 
			href, MB_YESNO|MB_ICONQUESTION) != IDYES ){
		exec_para = NULL;
		return FALSE;
	}
	return TRUE;
}

static int ExecuteHyperReference( char* href )
{
	int pos;
	int temp_page;
	char* tmpname;
	HINSTANCE hShell;

	if(*href != '#'){
		if( (pos = CheckHrefDvi(href, &g_szFileName[0])) >= 4){
			if(pos == 5){
				CoverSuspend();
				return Initialized_OpenDVI();
			}else if(pos == 4)
				hShell = ExecHref(g_winData.dviwin.hWnd, common_work);
			else if(pos == 0x10){
				DoMacro(common_work, HYPERTEX_SPECIAL);
				return 0;
			}
		}else{
			if(pos > 1 || exec_para != NULL)
				href = common_work;
			else if(base_href[0] != 0 && !strchr(href, ':')){
				strcpy(common_work, base_href);
				temp_page = strlen(common_work);
				while(--temp_page >= 0){
					if(  common_work[temp_page] == '/'
					  || common_work[temp_page] == ':')
						break;
				}
				if(href[0] == '/' || href[0] == '\\'){
					if(href[1] == '/'){
						if((tmpname = strchr(common_work, ':')) != NULL)
							strcpy(tmpname+1, href);
						else
							strcpy(common_work+temp_page, href);
					}else{
						if((tmpname = strstr(common_work, "//")) != NULL
							&& (tmpname = strchr(tmpname+2, '/')) != NULL)
							strcpy(tmpname, href);
						else
							strcpy(common_work+temp_page, href);
					}
				}else{
					if(href[0] == '.'){
						if(href[1] == '/')
							strcpy(common_work+ temp_page + 1, href+2);
						else if(href[1] == 0)
							common_work[temp_page+1] = 0;
						else if(href[1] == '.' && href[2] == 0)
							strcpy(common_work+ temp_page + 1, "../");
						else
							strcpy(common_work+ temp_page + 1, href);
					}else
						strcpy(common_work+ temp_page + 1, href);
				}
				href = common_work;
			}
			strcpy(common_work + 0x1000, 
				"Execute the above Hyper Jump");
			if(exec_para)
				sprintf(common_work + (0x1000 + 28), 
					" with the parameter:\n%s", exec_para);
			if( (!(f_hyper & F_H_DIRECT) || pos ) && !f_seamless &&
				MessageCBox(g_winData.hMainWnd, 
				 common_work + 0x1000, href,
				  MB_YESNO|MB_ICONQUESTION) != IDYES){
				exec_para = NULL;
				return FALSE;
			}
			hShell = ExecHref(g_winData.dviwin.hWnd, href);
		}
		if((UINT)hShell < 32){
			HyperReferenceError(href, 0);
			return 0;
		}
		return 0;
	}
	return DoHyperReference(href);
}

static int Initialized_OpenDVI(void ) // opendvi1
{
	if(!strstr(g_szFileName, ".dvi#")){
		f_killstop = f_kill;
		stop_level = 0;
	}
	return SendMessage(g_winData.dviwin.hWnd, WM_USER_FILE_OPEN, 0, 0 );
}

void HyperReferenceError( const char* href, int page )
{
	error(WARNING, 
		(href[1] == ' ')?
		"Cannot find '%s'":
		"Cannot resolve href %s", href);
	if(page > 0){
		ChgPage(page);
		ExpandPage();
	}
	if(f_hyper & F_H_DVIOPEN){				// <- ???
		f_hyper &= ~F_H_DVIOPEN;
		ShowDVI(NULL,NULL);
		return;
	}					
}

static int DoHyperReference( char* href )
{
	char* tmpname;
	int pos;
	POINT pt;
	int xx, yy;
	char *tmpstr;
	int temp_page;
	BYTE* pDibNew;

	if( href == NULL && (f_hyper & F_H_DVIOPEN) )
		href = hypertag;
	if( href == NULL ){
//				error( WARNING, "Hyper Jumping routine is called without "
//					"correct reference,\nwhich shall be ignored." );
		return 0;
	}
	if(g_winData.dviwin.pDib == NULL) return 0;
	CoverSuspend();
	tmpname = NULL;
	if(CheckRenew(1))
		ExpandPage();
	if(href[1] == ' ' && (pos = atoi(href+2)) > 0){	// "# <number>..."
		for(tmpname = href+2; *tmpname >= '0' && *tmpname <= '9'; tmpname++);						// skip digits
		if(*tmpname != '/'){				// "# <number>/...
			while(*tmpname == ' ')
				tmpname++;
			if(!*tmpname){					// "# <page>"
				return PostMessage(g_winData.dviwin.hWnd, WM_USER_NEW_PAGE, (WPARAM)pos, 0);		// jump to the given page
			}
			tmpname = NULL;
		}
	}
	if(GetH_NamePos(&pt, href+1) == 1){		// search the current page
#if	HYPER_2VERT
		if(IS_2VERT && pDib2 && IsSecondPage(GetCurrentPage()))
			pt.y += GetTextYSize();
#endif
		f_hyper |= F_H_CURRENTPAGE;
		ShowAtCenterAndLocateCursor(&g_winData.dviwin, pt.x, pt.y);
		AnimationPointer( &g_winData.dviwin, g_winData.dviwin.hWnd, g_winData.hInstance, pt.x, pt.y, FALSE );
		f_hyper &= ~F_H_DVIOPEN;
		return ShowDVI(NULL, &pt);
	}
	f_hist_msg = F_HM_HYPERJUMP;
	SaveH_Hist(&g_winData.dviwin, 1);
	xx = GetCurrentPage();

	tmpstr = dup_string(href);
	temp_page = SearchH_Name(tmpstr+1);		// search all pages
	strcpy(href, tmpstr);					// common_work may not be kept
	Free0(tmpstr);

	if(temp_page < 0){
href_er: 
		HyperReferenceError(href, xx);
		return 0;				// <-  ???
	}
	ChgPage(temp_page);
	ExpandPage();						// Expand in Buf
	pos = GetH_NamePos(&pt, href+1);	// get the position in Buffer
	if(!pos){
		error(C_MSG, "System error\n");
		HyperReferenceError(href,xx);
		return 0;
	}
	if(pos == -1){
		pt.x = ptex_d?(GetTextXSize()-1):0;
		pt.y = 0;
	}
	pDibNew = MakeBMP();						// get BMP
	f_hyper &= ~F_H_DVIOPEN;
	// ShowAtCenterAndLocateCursor(&g_winData.dviwin, pt.x, pt.y);	// Move cursor
#if	HYPER_2VERT
	if(IS_2VERT && IsSecondPage(temp_page))
		f_2page ^= 1;
#endif
	f_h_renew = TRUE;
href_search:
	if(!tmpname)
		return RenewDVI( &pDibNew, &pt );
	tmpname++;
	pos = strlen(tmpname);
	xx = tmpname[pos-1];
fs:	while(--pos >= 0 && tmpname[pos] != ' ');  
	if(pos >= 0 && xx == '\'' && tmpname[pos+1] != '\'')
		goto fs;									// 'file_name'
	while(--pos >= 0 && tmpname[pos] == ' ');		// cut source filename
	if(pos >= MAX_FIND_LEN-1 || pos < 0)
		return RenewDVI( &pDibNew, &pt );
	for(xx = 0; xx <= pos; xx++)
		szFind[xx] = tmpname[xx];		// get string to be searched
	szFind[xx] = 0;
//	SetSearchStr(szFind);
#if	DEB_SRCSER
	error(11, "sZfind[%s]\n", szFind);
#endif
	tmpname[pos] = xx;
	find_replace.Flags |= FR_DOWN;
	xx = yy = MAXINT;
	tmpname = GetNextSource(0, &pos);
	if(tmpname)
		xx = GetShiftInt(tmpname-4);
#if	DEB_SRCSER
	error(11, "[%p:%d ", tmpname-8, pos);
#endif
	tmpname = GetNextSource(1, &pos);
	if(tmpname)
		yy = GetShiftInt(tmpname-4);
#if	DEB_SRCSER
	error(11, ",%p:%d]\n(%d-%d", tmpname-8, pos, xx, yy);
#endif
	FindPt = -1;
	SearchStr(&g_winData.dviwin, &find_replace, 0);		// search in the current page
	for(FindPt = 0; (pos = GetSearchLoc(FindPt*2)) != 0 && xx >= pos; FindPt++)
#if	DEB_SRCSER
	error(11, ":%d", pos)
#endif
	;
#if	DEB_SRCSER
	error(11, ":%d)\n", pos);
#endif
	if(pos > 0){
		if(pos <= yy){					// find it
#if	DEB_SRCSER
	error(11, "Exists in this page!\n");
#endif
			FindPt--;
			goto sstr0;
		}
	}
	if(FindPt){
#if	DEB_SRCSER
		error(11, "Check former!\n");
#endif
		GetNextSource(-1,&xx);
		if(( tmpname = GetNextSource(-1,&xx)) == NULL
		  || GetShiftInt(tmpname-4) < GetSearchLoc((FindPt-1)*2) ){
			FindPt -= 2;
			goto sstr0;
		}
	}
	if(pos && yy != MAXINT)
		return RenewDVI( &pDibNew, &pt );
	ChgPage(FindPage+1);
	if(FindPage == GetCurrentPage())	// the next page doesn't exist
		return RenewDVI( &pDibNew, &pt );
	ExpandPage();
#if	DEB_SRCSER
	error(11, "Search in the next page!\n");
#endif
	if(!SearchStr(&g_winData.dviwin, &find_replace, 0))		// search in the next page
		goto not_hs;			 		// not exist
	tmpname = GetNextSource(2, &pos);
	xx = (tmpname)?GetShiftInt(tmpname - 4):MAXINT;
	if(GetSearchLoc(0) <= xx){			// find it
		ChgPage(FindPage-1);
sstr0:			f_DrawAnimationPointer = f_h_renew = FALSE;
		if(pDibNew)
			Free0(pDibNew + sizeof(BITMAPFILEHEADER));
		pDibNew = NULL;
#if	DEB_SRCSER
	error(11, "Find in the next page!\n");
#endif
		return SaveHistoryAndSearchStr();
	}
not_hs:
	if(pDibNew)
		Free0(pDibNew + sizeof(BITMAPFILEHEADER));
	pDibNew = GotoPage(FindPage-1);
	return RenewDVI( &pDibNew, &pt );
}

static int SaveHistoryAndSearchStr( void )
{
	char szText[MAX_FIND_LEN+1];
sstr:
	f_hist_msg = F_HM_SEARCH;
	SaveH_Hist(&g_winData.dviwin, 1);
	if(SearchStr(&g_winData.dviwin, &find_replace, 1))
		return ShowDVI(NULL,NULL);
	else{
		wsprintf( szText, "Target string = \"%s\"", szFindOld );
		ShowMessage(szText, "Not found", SM_OKCONT);
		return ReOpen(FALSE);
	}
}

void DVIWIN_OnVScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos)
{
	/* If the message is sent from a scroll bar, hwndCtrl is a handle to the scroll bar control.
	   Otherwise, it is NULL.
	   code is one of the followings: SB_BOTTOM, SB_ENDSCROLL, SB_LINEDOWN, SB_LINEUP,
									SB_PAGEDOWN, SB_PAGEUP, SB_THUMBPOSITION, SB_THUMBTRACK, SB_TOP.
	   pos indicates the current position of the scroll bar if code is either SB_THUMBPOSITION or SB_THUMBTRACK. */
	int nVscrollInc;

	switch( code ){
		case SB_TOP:
			nVscrollInc = -g_winData.dviwin.nVscrollPos;
			break;
		case SB_BOTTOM:
			nVscrollInc = g_winData.dviwin.nVscrollMax - g_winData.dviwin.nVscrollPos;
			break;
		case SB_LINEUP:
			nVscrollInc = -f_scr_skip;
			break;
		case SB_LINEDOWN:
			nVscrollInc = f_scr_skip;
			break;
		case SB_PAGEUP:
			nVscrollInc = -g_winData.dviwin.cyClient*9/10;
			break;
		case SB_PAGEDOWN:
			nVscrollInc = g_winData.dviwin.cyClient*9/10;
			break;
		case SB_THUMBPOSITION:
		case SB_THUMBTRACK:
			nVscrollInc = pos - g_winData.dviwin.nVscrollPos;
			break;
		default:
			nVscrollInc = 0;
			break;
	}
	SendMessage( hwnd, WM_USER_VSCROLL, nVscrollInc, 0 );
	return;
}

void DVIWIN_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos)
{
	int nHscrollInc;
	switch( code ){
		case SB_LINEUP:
			nHscrollInc = -f_scr_skip;
			break;
		case SB_LINEDOWN:
			nHscrollInc = f_scr_skip;
			break;
		case SB_PAGEUP:
			nHscrollInc = -g_winData.dviwin.cxClient*9/10;
			break;
		case SB_PAGEDOWN:
			nHscrollInc = g_winData.dviwin.cxClient*9/10;
			break;
		case SB_THUMBPOSITION:
			nHscrollInc = pos - g_winData.dviwin.nHscrollPos;
			break;
		case SB_THUMBTRACK:
			nHscrollInc = pos - g_winData.dviwin.nHscrollPos;
			break;
		default:
			nHscrollInc = 0;
			break;
	}
	SendMessage( hwnd, WM_USER_HSCROLL, nHscrollInc, 0 );
	return;
}

void DVIWIN_OnUserVScroll( HWND hwnd, int nVscrollInc ) /* vscroll */
{
	BOOL b = FALSE;
	int pos;
/*
	IsSecondPage()      (g_winData.dviwin.pDib, pDib2)     (pDib2, g_winData.dviwin.pDib)
	(ODD, EVEN)  1                 1          0
	(EVEN, ODD)  0                 1          0
*/
	if(IS_2VERT && b_presentation_mode && g_winData.dviwin.pDib){
		if(g_winData.dviwin.nVscrollMax == g_winData.dviwin.nVscrollPos && nVscrollInc > 0){
			pos = GetCurrentPage();
			if(!IsSecondPage(pos))
//			if(IS_2DIB2)
				pos++;					// (pDib2, g_winData.dviwin.pDib)
			if(pos >= GetTotalPage())
				goto vskip;
			nVscrollInc = -GetTextYSize();
vcscrl:		ChgPage(pos);
			f_2page ^= F_ODD2EVEN;
			CoverSuspend();
			SaveH_Hist(&g_winData.dviwin, 1);
			SetPageMoveButtons( &g_winData.dviwin );
			ExpandPage();
			ReplaceBmp(&g_winData.dviwin, MakeBMP());	// g_winData.dviwin.pDib
			Get2Bmp();						// pDib2
			SetPoint(0, nVscrollInc, -3);
			nVscrollInc /= GetYGray();
			b = TRUE;
		} else if(g_winData.dviwin.nVscrollPos == 0 && nVscrollInc < 0){
			pos = GetCurrentPage() - 1;
			if(!IsSecondPage(pos))
				pos--;				// (pDib2, g_winData.dviwin.pDib)
			if(pos <= 0)
				goto vskip;
			nVscrollInc = GetTextYSize();
			goto vcscrl;
		}
	}
vskip:
	nVscrollInc = max( -g_winData.dviwin.nVscrollPos,
			   min( nVscrollInc, g_winData.dviwin.nVscrollMax - g_winData.dviwin.nVscrollPos ) );
	if( nVscrollInc != 0 ) { /* || message == WM_USER_VSCROLL){ */
		g_winData.dviwin.nVscrollPos += nVscrollInc;
		ScrollWindow( g_winData.dviwin.hWnd, 0, -nVscrollInc, NULL, NULL );
		if( f_flatscroll && GetVersionLevel() > 0 ){
			g_FlatSB_SetScrollPos( g_winData.dviwin.hWnd, SB_VERT, g_winData.dviwin.nVscrollPos, TRUE );
		} else{
			SetScrollPos( g_winData.dviwin.hWnd, SB_VERT, g_winData.dviwin.nVscrollPos, TRUE );
		}
		if(b){
			ShowDVI(NULL, NULL);
			return;
		}
		UpdateWindow( g_winData.dviwin.hWnd );
	}
	return;
}

void DVIWIN_OnUserHScroll( HWND hwnd, int nHscrollInc ) /* hscroll */
{
	nHscrollInc = max( -g_winData.dviwin.nHscrollPos,
					   min( nHscrollInc, g_winData.dviwin.nHscrollMax - g_winData.dviwin.nHscrollPos ) );
	if( nHscrollInc != 0 ){
		g_winData.dviwin.nHscrollPos += nHscrollInc;
		ScrollWindow( g_winData.dviwin.hWnd, -nHscrollInc, 0, NULL, NULL );
		if( f_flatscroll && GetVersionLevel() > 0 ){
			g_FlatSB_SetScrollPos( g_winData.dviwin.hWnd, SB_HORZ, g_winData.dviwin.nHscrollPos, TRUE );
		} else{
			SetScrollPos( g_winData.dviwin.hWnd, SB_HORZ, g_winData.dviwin.nHscrollPos, TRUE );
		}
		UpdateWindow( g_winData.dviwin.hWnd );
	}
}

void DVIWIN_OnTouch( HWND hwnd, UINT cInputs, HTOUCHINPUT hTouchInput )
{
	PTOUCHINPUT pInputs = (PTOUCHINPUT)malloc( cInputs*sizeof(TOUCHINPUT) );
	if( pInputs ){
		if( GetTouchInputInfo(hTouchInput, cInputs, pInputs, sizeof(TOUCHINPUT)) ){
			// process pInputs
			if( !CloseTouchInputHandle(hTouchInput) ){
				// error handling
			}
		} else{
			// GetLastError() and error handling
		}
		free( pInputs );
	} else{
		// error handling, presumably out of memory
	}
	DefWindowProc(hwnd, WM_TOUCH, MAKEWPARAM(cInputs,0), (LPARAM)hTouchInput);
}

void DVIWIN_OnChar(HWND hwnd, TCHAR ch, int cRepeat)
{
	int id_value;
	if(	 ch < 0x80 && (id_value = key_trans[key_table[ch]].id) != 0 )
		SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(id_value,0), 0);
	return;
}

void DVIWIN_OnClose(HWND hwnd)
{
	if( b_presentation_mode ) SendMessage( hwnd, WM_COMMAND, MAKEWPARAM(ID_PRESENTOFF,0), 0L );
	return;
}

void DVIWIN_OnDestroy(HWND hwnd)
{
	if( g_winData.dviwin.pDib != NULL ){
		FreeBmp( g_winData.dviwin.pDib );
		g_winData.dviwin.pDib = NULL;
		if(!f_quit){
			WriteHistory("FILE");
			if(f_fkeep)	keep_font_path();
		}
	}
	if(pDibPen)	FreeBmp(pDibPen);
	pDibPen = NULL;
	return;
}

void DVIWIN_OnUserHistoryOpen(HWND hwnd, int page, BOOL bFileHistory)
{
	char fname[MAX_PATH];
	int size;

	if( bFileHistory ){
		page &= (MAX_F_HIST - 1);
		if( HIBYTE(GetKeyState(VK_SHIFT)) && !HIBYTE(GetKeyState(VK_CONTROL)) ){
			strncpy(fname, f_hist[page].name, MAX_PATH);
			size = strlen(fname);
			while(size && fname[size] != '\\' && fname[size] != ':') /* TODO: This may not work with S-JIS. */
				size--;		// cut the file name
			if(size){
				fname[size+1] = 0;
				size = GetFileAttributes(fname);
				if(size != INVALID_FILE_ATTRIBUTES
				  && (size & FILE_ATTRIBUTE_DIRECTORY)
				  && QueryFileName(fname)){
					if(HIBYTE(GetKeyState(VK_SHIFT)))
						SetStartPage(30000);
					SetColor(4);
					Initialized_OpenDVI();
				}
				return;
			}
		}

		if(strcmp(current_name, f_hist[page].name)){
			if(access(f_hist[page].name, 0)){
				if(MessageCBox(g_winData.hMainWnd, 
					"Cannot find the above file!\n"
					"Erace from History?",
					f_hist[page].name, MB_YESNO|MB_ICONQUESTION) == IDYES){
					EraceHistory(page);
				}
					return;
			}
			SetColor(4);
			DefineDVIFileName( f_hist[page].name );
			if(!HIBYTE(GetKeyState(VK_CONTROL)))
				SetStartPage(f_hist[page].page);
			else if(HIBYTE(GetKeyState(VK_SHIFT)))
				SetStartPage(30000);
			Initialized_OpenDVI();
			return;
		}

		if(!(page = f_hist[page].page - GetCurrentPage())) return;
		f_hist_msg = F_HM_HYPERJUMP;
		ShowNewPage(page);
		return;
	}else{
		POINT pt;
		if(page < MAX_H_HIST)
			h_hist_pt = page;
		pt.x = h_hist[page].x;
		pt.y = h_hist[page].y;
		page = h_hist[page].page;
		JumpHistory( page, 0, pt );
	}
	return;
}

void DVIWIN_OnUserFindNext( HWND hwnd )
{
	if( find_replace.Flags & FR_DOWN ){
		SendMessage( hwnd, WM_COMMAND, MAKEWPARAM(ID_NEXTCAND,0), 0L );
	} else{
		SendMessage( hwnd, WM_COMMAND, MAKEWPARAM(ID_PRECAND,0), 0L );
	}
}

void DVIWIN_OnUserExecMacro( HWND hwnd )
{
	if( timer_id == id_page ){
		timer_id = 0;
		if(waiting_macro[0]){
			int size = strlen(waiting_macro);
			DoMacro(waiting_macro, waiting_macro_mode);
			if(  size != strlen(waiting_macro)	// multiple ;
			  || waiting_macro_mode != 1)		// not dviout special
				return;
			waiting_macro[0] = 0;
		}
		ExecMacro(1);
	}else
		waiting_macro[0] = 0;
	return;
}

void DVIWIN_OnDropFiles( HWND hwnd, HDROP hDrop )
{
	char fname[MAX_PATH];
	int size;
	DragQueryFile( hDrop, 0, fname, sizeof(fname));
	if( (size = strlen(fname)) > 4 && !stricmp(fname + size - 4, ".lnk") ){
		ChangeLinkToReal(fname);
		size = strlen(fname);
	}

	/* Drop file MUST have an extension either .dvi or .tar */
	if( size < 4 ||
		(strcmpi(fname + size - 4, ".dvi") != 0 && strcmpi(fname + size - 4, ".tar") != 0) ) return;
	DefineDVIFileName( fname );
	DragFinish( hDrop );
	SetColor(4);

	Initialized_OpenDVI();
}

void DVIWIN_OnUserFileOpen( HWND hwnd )
{
	/* Open a file defined at g_szFileName. */
	char* tmpname;
	int pos;
	char fname[MAX_PATH];
	char* href;

opendvi:
	if( g_winData.dviwin.pDib != NULL ){
		FreeBmp( g_winData.dviwin.pDib );
		g_winData.dviwin.pDib = NULL;
	}
	CheckPenBuf();

	if( (tmpname = strstr(g_szFileName, ".dvi#")) != NULL){
		pos = 0;
		if(tmpname[5] == ' ' && (pos = atoi(tmpname+6)) > 0){
			int size = 5;
			while(tmpname[++size] >= '0' && tmpname[size] <= '9');
			while(tmpname[size] == ' ')
				size++;
			if(tmpname[size] != 0)		// source special
				pos = 0;
		}
		if(pos)
			SetStartPage(pos);
		else
			SetHyperTag(tmpname + 4);
		tmpname[4] = 0;
	}

	pos = f_renew;
	f_renew = 0;
	SetForegroundWindow( g_winData.hMainWnd );
	f_renew = pos;
	CheckStop(2);
reopendvi:
	ChangeWaitCursor(1);
	if( (g_winData.dviwin.pDib = ReadDIB( g_szFileName )) == NULL
		&&	g_szFileName2[0] != 0
		&& (g_winData.dviwin.pDib = ReadDIB(g_szFileName2)) != NULL )
			strcpy(g_szFileName, GetOpenName());
		else
			g_szFileName2[0] = 0;
	ChangeWaitCursor(0);
	if( g_winData.dviwin.pDib == NULL ){
		int size;
		if(pDibKeep){
			FreeBmp(pDibKeep);
			pDibKeep = NULL;
		}
		if(g_nErrorCode) goto chkerr;
		strncpy(fname, g_szFileName, MAX_PATH);
		size = strlen(fname);
		if(size > 4 && strcmp(fname + size - 4, ".dvi") == 0)
			fname[size-4] = 0;
		size = strlen(fname);
		if(size && fname[size - 1] == '\\')
			fname[--size] = 0;
		pos = GetFileAttributes(fname);
		if(pos != 0xffffffff && (pos & FILE_ATTRIBUTE_DIRECTORY)){
			g_szFileName[0] = 0;
			if ((pos = QueryFileName(fname))!= 0)
				goto reopendvi;
		}
		if(pos)
chkerr:
		CheckError();
		EnableButton( FALSE );
		if( g_szFileName[0] ){
			SetStartPage(PrevPage);
			SendMessage( g_winData.hMainWnd, WM_USER_FILE_OPEN, 0, 0 );
			return;
		}
		return;
	}
	EnableButton( TRUE );
	SaveH_Hist(&g_winData.dviwin, 0);
	if((f_hyper & F_H_DVIOPEN) && hypertag != NULL){
		href = hypertag;
		if(pDibKeep){
			FreeBmp(pDibKeep);
			pDibKeep = NULL;
		}
		DoHyperReference(href);
		return;
	}
	if(IS_2PAGE) Get2Bmp();
	f_h_renew = FALSE;
show:
	ShowDVI(NULL,NULL);
	return;
}

void DVIWIN_OnPaint( HWND hwnd )
{
	SendMessage( g_winData.toolbar.hWndFindCombo, CB_SHOWDROPDOWN, FALSE, 0 );
	ViewBmpFile( g_winData.dviwin.pDib, g_winData.dviwin.nHscrollPos, g_winData.dviwin.nVscrollPos );
	return;
}

BOOL DVIWIN_OnAppCommand(HWND hwnd, HWND hWndClicked, int cmd, int uDevice, int dwKeys)
{
	/* Now, IntelliMouse (and such special input devices) are supported by a standard
	message defined after Windows 2000, NOT HARD CODING. */

	switch( cmd ){
		case APPCOMMAND_BROWSER_BACKWARD: // 1
			SendMessage( hwnd, WM_COMMAND, MAKEWPARAM(ID_FORMERHIST,0), 0L );
			return TRUE;
		case APPCOMMAND_BROWSER_FORWARD: // 2
			SendMessage( hwnd, WM_COMMAND, MAKEWPARAM(ID_NEXTHIST,0), 0L );
			return TRUE;
		default:
			return FALSE;
	}
	return FALSE;
}

UINT DVIWIN_OnNCHitTest(HWND hwnd, int x, int y)
{
	/* WM_NCHITTEST is sent ALWAYS BEFORE generating mouse messages,
	   that is, if this returns, e.g., HTCAPTION, the window behaves
	   just like that the pointer is on the title bar. 
	   the x and y coordinates are in the screen coordinate.
	*/
	return FORWARD_WM_NCHITTEST(hwnd, x, y, DefWindowProc);
}

void DVIWIN_OnNCMouseMove(HWND hwnd, int x, int y, UINT codeHitTest)
{
	switch( codeHitTest ){
		case HTHSCROLL:
		case HTVSCROLL:
			if( g_winData.dviwin.bHand ){
				ChangeMouseCursor( CS_NORMAL );
			}
			break;
		default:
			break;
	}
}

void DVIWIN_OnNCLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest)
{
	switch( codeHitTest ){
		case HTHSCROLL:
		case HTVSCROLL:
			if( g_winData.dviwin.bHand ){
				ChangeMouseCursor( CS_NORMAL );
			}
			break;
		default:
			break;
	}
	FORWARD_WM_NCLBUTTONDOWN(hwnd, fDoubleClick,x,y,codeHitTest,DefWindowProc);
}

void DVIWIN_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
	BYTE* pDibNew = NULL; 		 // DIBのﾎﾟｲﾝﾀ 
	char* href = NULL;
	char* tmpname;
	BOOL *toggle;
	FILE *fp;
//	HDC	  hdc;			// ﾃﾞﾊﾞｲｽｺﾝﾃｷｽﾄ -- 未使用
	POINT pt;
	int	 temp_page;
	int	 size;
	int	 pos;
	int	 xx, yy;
	char  fname[MAX_PATH];
	static RECT rc;
	int inf_size;
	static BOOL bShowingHref = FALSE;
	static LONG wl = 0;
	static COLORREF wbk_color;
	static LONG wlc = 0;
	static int bOnHref = FALSE;
	static int bOnHrefPress = FALSE;


wmcmd:
	switch( id ){
		static int old_XGray, old_YGray;
		static int old_e;
		static BOOL old_varf;
		static char old_y[0x20];
		HMENU  hsubmenu;
		RECT   subrect;

		case ID_ALTF:
		case ID_ALTJ:
		case ID_ALTS:
		case ID_ALTD:
		case ID_ALTV:
		case ID_ALTN:
		case ID_ALTP:
		case ID_ALTO:
		case ID_ALTH:
			pos = id - ID_ALTF;
			hsubmenu = GetMenu(g_winData.hMainWnd);
			if(GetMenuState(hsubmenu, pos, MF_BYPOSITION) & MFS_GRAYED)
				break;
			if(!GetMenuItemRect(g_winData.hMainWnd, hsubmenu, pos, &subrect))
				GetWindowRect(g_winData.hMainWnd, &subrect);
			hsubmenu = GetSubMenu(hsubmenu, pos);
			HiliteMenuItem(g_winData.hMainWnd, g_winData.hMenu, 
				pos, MF_BYPOSITION|MFS_HILITE);
//			SetMenuDefaultItem(hsubmenu, 0, FALSE);
			TrackPopupMenuEx(hsubmenu, 
				TPM_HORIZONTAL|TPM_LEFTALIGN|TPM_LEFTBUTTON, 
				subrect.left, subrect.bottom, g_winData.hMainWnd, NULL);
			HiliteMenuItem(g_winData.hMainWnd, g_winData.hMenu, 
				pos, MF_BYPOSITION|MFS_UNHILITE);
			break;

		case ID_WINMAX:
			ShowWindow(g_winData.hMainWnd, SW_SHOWMAXIMIZED);
			break;

		case ID_DEFIT:
			if(!f_FIT) return;
			SetParaInt("e", old_e);
			SetParaFlag("varf", old_varf);
			SetXYGray(old_XGray, old_YGray);
			SetParaString("y", old_y);
			f_FIT = 0;
				goto chk_re_open;

		case ID_FIT:
		case ID_FULL:
			if( g_winData.dviwin.pDib == NULL || !g_winData.dviwin.cxClient || !g_winData.dviwin.cyClient
			  || (b_presentation_mode && f_FIT == id) ) return;
			if(f_init){
				SetStartPage(GetCurrentPage());
				ExpandPage();
			}
			size = 	((IS_2HORI)?2:1)*GetTextXSize()*0x1000/g_winData.dviwin.cxClient;
			pos  =	((IS_2VERT)?2:1)*GetTextYSize()*0x1000/g_winData.dviwin.cyClient;
			if(id == ID_FIT){
				if(size < pos)
					size = pos;
			}else if(size > pos)
				size = pos;
			if(b_presentation_mode){
				double dxx, dyy;
					if((inf_size = GetParaInt("e")) == 0)
					inf_size = 1000;
				xx = size * 1000/inf_size;	// xx: size*0x1000 if -e=0
				if(xx < 0x800 || xx > 0x80000) return;
				else if(xx < 0x1400)
					pos = 1;
				else if(xx < 0x2400)
					pos = 2;
				else
					pos = (xx+0x800)/0x1000;	// pos: gray scale
				size = pos*(0x1000*1000)/size;	// scale par current
				SetXYGray(pos, pos);
				if(size > 990 && size < 1010)
					size = 1000;
				dxx = (4736286.72+OX)*1000/inf_size - 4736286.72; // = original OX
				dyy = (4736286.72+OY)*1000/inf_size - 4736286.72; // = original OY
				inf_size = inf_size*size/1000;	// real scale
				OX = dxx*inf_size/1000 + 4736286.72*(inf_size-1000)/1000;
				OY = dyy*inf_size/1000 + 4736286.72*(inf_size-1000)/1000;
				SetParaInt("e", (inf_size == 1000)? 0:inf_size);
				SetParaFlag("varf", TRUE);
				xx = GetTextXSize()*size/1000;
				if(IS_2HORI)
					xx *= 2;
						yy = GetTextYSize()*size/1000;
				if(IS_2VERT)
					yy *= 2;
				CoverChange(size);
					size = g_winData.dviwin.cxClient*pos;
				pos *= g_winData.dviwin.cyClient;
				if(id == ID_FULL){
					while(xx > size && yy > pos){
						xx--;
						yy--;
					}
					if(xx < size)
						xx = size;
					if(yy < pos)
						yy = pos;
				}else{
					if(xx > size)
						xx = size;
					if(yy > pos)
						yy = pos;
					while(xx < size && yy < pos){
						xx++;
						yy++;
					}
					if(xx < size && xx*100 > size*99)
						xx = size;
					if(yy < pos && pos*100 > size*99)
						yy = pos;
				}
				sprintf(common_work, "-y=F%ddot/%ddpi:%ddot/%ddpiP",
					IS_2HORI?(xx/2):xx, GetXDpi(), 
					IS_2VERT?(yy/2):yy, GetYDpi());
				f_FIT = 0;
				SetPara(common_work, SET_OPTION);
				f_FIT = id;
				g_winData.dviwin.cover_sheet.bArrangeForPause = TRUE;
				goto chk_re_open;
			}else{
				pos = size/0x1000;
				if(pos > 127) return;
				SetXYGray(pos + 1, pos + 1);
			}
			CheckView(-1);
			goto newbmp;

		case ID_REDUCE:
			size = 1;
			goto resize;

		case ID_MAGNIFY:
			size = -1;
resize:
			if(g_winData.dviwin.pDib == NULL) return;
			if(ChgGray(size, 64) == 0)
				break;
			if(pDibPen)
				f_KeepDraw = TRUE;
			CheckView(-1);
newbmp:	
			pt = GetDVICoordFromClient(&g_winData.dviwin, g_winData.dviwin.cxClient/2, g_winData.dviwin.cyClient/2);
chgbmp:
			if(FindPt >= 0 && FindDvi == id_dvi 
				  && FindPage == GetCurrentPage())
				SetColor(8);
			else
				FindPt = -1;
			if(IS_MPAGE){
				pos = f_2top;
				xx = f_2page;
				if(ReplaceBmp(&g_winData.dviwin, GotoPage(pos)) == FALSE) return;
				if(xx & 0x2000){
					Show16Pages();
					return;
				}
				goto id_cross;
			}
			if(f_ucolor & 14){		/* Use anti-Areasing, fit BMP */
				ChangeWaitCursor(1);
				SetStartPage(GetCurrentPage());
				if(g_winData.dviwin.pDib)
					FreeBmp(g_winData.dviwin.pDib);
				CheckPenBuf();
				g_winData.dviwin.pDib = ReadDIB( g_szFileName );
				ChangeWaitCursor(0);
				if(g_winData.dviwin.pDib == NULL)
					break;
			}else if(ReplaceBmp(&g_winData.dviwin, MakeBMP()) == FALSE)
				break;
			if(FindPt >= 0)
				ShowFound(&g_winData.dviwin, s_box, s_box_pt, f_s_color, FindPt);
			SetScrollPosToMakePointInBufferCenterOfWindow(&g_winData.dviwin, pt.x, pt.y);
show0:
			ShowDVI0( NULL );
			return;

		case ID_SCALE1:
		case ID_SCALE2:
		case ID_SCALE3:
		case ID_SCALE4:
			size = id - ID_SCALE1;
			 if(g_winData.dviwin.pDib == NULL) return;
			pt = GetDVICoordFromClient(&g_winData.dviwin, g_winData.dviwin.cxClient/2, g_winData.dviwin.cyClient/2);
			SetGamma(scale[size].gamma);
			SetXYGray(scale[size].x, scale[size].y);
			CheckView(size);
			goto chgbmp;

		case ID_RESCUTEDGE:
			if(!g_winData.dviwin.pDib) return;
			CutEdge(-1);
			f_cutedge = 0;
			ReOpen(FALSE);
			return;
		
		case ID_CUTEDGE1:
			if(!g_winData.dviwin.pDib || f_cutedge) return;
			f_cutedge = 1;
			CutEdge(1);
			ReOpen(FALSE);
			return;
			 
		case ID_CUTEDGE:
			if(!g_winData.dviwin.pDib) return;
			CutEdge(0);
			f_cutedge = 0;
			ReOpen(FALSE);
			return;

/* The followings are codes for 4, 16-page mode.
   However, there is a bug that selecting twice
   make the page go ahead 3 or 15 pages.
   Why?? */
		case ID_16PAGE:
id_16page:
			Show16Pages();
			return;

		case ID_CROSS:
id_cross:
			Show4Pages();
			return;

		case ID_ONEPAGE:
			if(!f_2page)
				break;
			pos = 0;
		case ID_DOUBLE:
		case ID_RDOUBLE:
		case ID_VDOUBLE:
			if(g_winData.dviwin.pDib==NULL)
				break;
			CheckMenu(ID_DOUBLE, 0);
			CheckMenu(ID_RDOUBLE, 0);
			CheckMenu(ID_VDOUBLE, 0);
			if(GetTotalPage() < 2)
				goto onepage;
			if(IS_2PAGE){
				if(id == ID_ONEPAGE)
					goto onepage;
				pos = 0;
				if(IS_2REV){
					if(id == ID_DOUBLE){			// 2 Rev -> 2 Norm
						f_2page &= ~F_2REV;
						goto f2chg;
					}else if(id == ID_VDOUBLE)	// 2 Rev -> 2 Vert
						pos = 1;
				}else if(!IS_2VERT){
					if(id == ID_RDOUBLE){			// 2 Norm -> 2 Rev
						f_2page = 0;
						goto f2chg;
					}else if(id == ID_VDOUBLE)	// 2 Norm -> 2 Vert
						pos = 1;
				}else if(id != ID_VDOUBLE)		// 2 Vert -> 2 Norm, 2 Rev
					pos = 1;
				else if(f_FIT) return;			// 2 Vert -> 2 Vert
onepage:
				if(IsSecondPage(GetCurrentPage()))		// 2 -> Norm
					ChgPage(GetCurrentPage()-1);
				f_2page = 0;
				Clear2Page();
				ExpandPage();
				g_winData.dviwin.cover_sheet.bArrangeForPause = TRUE;
				if(ReplaceBmp(&g_winData.dviwin, MakeBMP())){
					if(pos)
						goto f2chg;
					ShowDVI(NULL, NULL);
					return;
				}
				break;
			}else{
				if(f_rpcolor == 5)
					goto f2renew;
				if(IS_MPAGE){
					ChgPage(f_2top);
f2renew:
					f_2page = 0;
					ClearKeepBMP();
					ExpandPage();
					g_winData.dviwin.cover_sheet.bArrangeForPause = TRUE;
					ReplaceBmp(&g_winData.dviwin, MakeBMP());
					if(g_winData.dviwin.pDib == NULL) return;
				}
f2chg:	
				CheckMenu(id, 1);
				if(IS_2PAGE){
					ShowDVI(NULL,NULL);
					return;
				}
				f_2page = ((id==ID_VDOUBLE)?F_2VERT:F_2PAGE)|(GetCurrentPage()&1)
					|((id==ID_RDOUBLE)?F_2REV:0);
			}
			if((pDibNew = g_winData.dviwin.pDib) != NULL)
				pDibNew -= sizeof(BITMAPFILEHEADER);
			RenewDVI( &pDibNew, NULL );
			return;

		case ID_BLACKER:
			if(g_winData.dviwin.pDib == NULL) return;
			pDibNew = Blacker();
			RenewDVI( &pDibNew, NULL );
			return;

		case ID_WHITER:
			if(g_winData.dviwin.pDib == NULL) return;
			pDibNew = Whiter();
			RenewDVI( &pDibNew, NULL );
			return;

		case ID_TOREVERSE:
			if(SetGamma(0) > 0){
scr_rev:
				SetGamma(-SetGamma(0));
				ReOpen(TRUE);
				return;
			}
			return;

		case ID_TONORMAL:
			if(SetGamma(0) < 0)
				goto scr_rev;
			return;

		case ID_REVERSE:
to_reverse:
			if(g_winData.dviwin.pDib == NULL) return;
			SetGamma(-SetGamma(0));
			ReOpen(FALSE);
			return;

		case ID_DRLINE:
		case ID_DRBOX:
			CheckMenuSet(id, ID_DRLINE, ID_DRBOX);
			g_winData.draw_style = id - ID_DRLINE;
inipm:
			if(g_winData.hWndPresenMenu)
				SendMessage( g_winData.hWndPresenMenu, WM_INITDIALOG, 0, 0 );
			return;

		case ID_DRERACE:
			SetPoint(0, 0, -2);
			ShowDVI(NULL, NULL);
			return;

		case ID_DRRED:
		case ID_DRBLACK:
		case ID_DRBLUE:
		case ID_DRGREEN:
			CheckMenuSet(id, ID_DRRED, ID_DRGREEN);
			g_winData.draw_color = (id - ID_DRRED)|(g_winData.draw_color&F_DTHICK);
			goto inipm;

		case ID_DTHICK:
			g_winData.draw_color ^= F_DTHICK;
			CheckMenu(ID_DTHICK, g_winData.draw_color&F_DTHICK);
			goto inipm;

		case ID_BMARKPAGE:
			if((id = GetUserKey(4)) != 0)
				goto wmcmd;
			id = ID_MARKPAGE;
		case ID_MARKPAGE:
		case ID_MARKRANGE:
			MessageBeep(MB_OK);
			SaveH_Hist(&g_winData.dviwin, id - (ID_MARKPAGE-2));
			if(id == ID_MARKRANGE){
				if( h_hist[PAGE_MARK].id != id_dvi )
					SaveH_Hist(&g_winData.dviwin, 2);
			}
			if( h_hist[RANGE_MARK].id == id_dvi )
				SetMarkRange( h_hist[PAGE_MARK].page,
					h_hist[RANGE_MARK].page );
			return;

		case ID_BGOMARK:
			if((id = GetUserKey(5)) != 0)
				goto wmcmd;

		case ID_GOMARK: /* Go to mark */
		case ID_EXMARK: /* Exchange Mark */
			if(h_hist[PAGE_MARK].id != id_dvi || g_winData.dviwin.pDib == NULL) return;
			f_hist_msg = F_HM_MARK;
			SaveH_Hist(&g_winData.dviwin, 1);
			pt.x = h_hist[PAGE_MARK].x;
			pt.y = h_hist[PAGE_MARK].y;
			temp_page = h_hist[PAGE_MARK].page;
			if(id == ID_EXMARK)
				SaveH_Hist(&g_winData.dviwin, 2);
			size = 0;
			JumpHistory( temp_page, size, pt );
			return;

		case ID_TOPPAGE:
			if(g_winData.dviwin.pDib == NULL) return;
			temp_page = -GetTotalPage();
			if( hwndCtl == g_winData.toolbar.hWndToolBar && f_rev_movebutton )
				temp_page *= -1;
			ShowNewPage(temp_page);
			return;

		case ID_LASTPAGE:
			if(g_winData.dviwin.pDib == NULL) return;
			temp_page = GetTotalPage();
			if( hwndCtl == g_winData.toolbar.hWndToolBar && f_rev_movebutton )
				temp_page *= -1;
			ShowNewPage(temp_page);
			return;

		case ID_DOWNPAGE:
			DownPage();
			return;

		case ID_UPPAGE:
uppage:
			if(g_winData.dviwin.pDib == NULL || GetCurrentPage() <= 1) return;
			SaveH_Hist(&g_winData.dviwin, 1);
			if(IS_MPAGE){
				int pos, xx;
				if(f_2top <= 1) return;
				pos = f_2top - (IS_16PAGE?16:4);
				xx = f_2page;
				if(ReplaceBmp(&g_winData.dviwin, GotoPage(pos)) == FALSE) return;
				if(xx & 0x2000){
					Show16Pages();
					return;
				}
				Show4Pages();
			}
			if(ReplaceBmp(&g_winData.dviwin, nextpage(GetShiftPage(-1))) == FALSE) return;
			ScrollWindow( g_winData.dviwin.hWnd, 0, 
				g_winData.dviwin.nVscrollMax - g_winData.dviwin.nVscrollPos, NULL, NULL );
			if( f_flatscroll && GetVersionLevel() > 0 )
			{
				g_FlatSB_SetScrollPos( g_winData.dviwin.hWnd, SB_VERT,
					g_winData.dviwin.nVscrollPos = g_winData.dviwin.nVscrollMax, TRUE );
			}
			else
			{
				SetScrollPos( g_winData.dviwin.hWnd, SB_VERT,
					g_winData.dviwin.nVscrollPos = g_winData.dviwin.nVscrollMax, TRUE );
			}
			ShowDVI0( NULL );
			return;

		case ID_NEXTPAGE:
			temp_page = 1;
			if( hwndCtl == g_winData.toolbar.hWndToolBar && f_rev_movebutton ) temp_page *= -1;
			if( HIBYTE(GetKeyState(VK_SHIFT)) )
			temp_page *= 5;
			if( HIBYTE(GetKeyState(VK_CONTROL)) )
				temp_page *= 10;
new_page:
			if(g_winData.dviwin.pDib == NULL) return;
nxtpg:
			ShowNewPage( temp_page );
			return;

		case ID_BFORMERHIST:
			if((id = GetUserKey(2)) != 0)
				goto wmcmd;

		case ID_FORMERHIST:
			size = -1;
			if(h_hist_pt == h_hist_n){
				f_hist_msg = F_HM_HISTORY;
				SaveH_Hist(&g_winData.dviwin, 1);
			}
idhist:
			GetH_Hist(&pt, &temp_page, size);
			if( !JumpHistory( temp_page, size, pt ) ) break;
			return;

		case ID_BNEXTHIST:
			if((id = GetUserKey(3)) != 0)
				goto wmcmd;

		case ID_NEXTHIST:
			size = 1;
nxthst:
			if(h_hist_pt == h_hist_n)
				break;
			goto idhist;

		case ID_QUITHIST:
			size = 0;
			goto nxthst;

		case ID_PREVPAGE:
			temp_page = -1;
			if( hwndCtl == g_winData.toolbar.hWndToolBar && f_rev_movebutton ) temp_page *= -1;
			if( HIBYTE(GetKeyState(VK_SHIFT)) )
				temp_page *= 5;
			if( HIBYTE(GetKeyState(VK_CONTROL)) )
				temp_page *= 10;
			goto new_page;

		case ID_50PAGE:
			temp_page = 50;
			ShowNewPage(temp_page);
			return;
		case ID_20PAGE:
			temp_page = 20;
			ShowNewPage(temp_page);
			return;
		case ID_10PAGE:
			temp_page = 10;
			ShowNewPage(temp_page);
			return;
		case ID_5PAGE:
			temp_page = 5;
			ShowNewPage(temp_page);
			return;
		case ID_2PAGE:
			temp_page = 2;
			ShowNewPage(temp_page);
			return;
		case ID_m2PAGE:
			temp_page = -2;
			ShowNewPage(temp_page);
			return;
		case ID_m5PAGE:
			temp_page = -5;
			ShowNewPage(temp_page);
			return;
		case ID_m10PAGE:
			temp_page = -10;
			ShowNewPage(temp_page);
			return;
		case ID_m20PAGE:
			temp_page = -20;
			ShowNewPage(temp_page);
			return;
		case ID_m50PAGE:
			temp_page = -50;
			ShowNewPage(temp_page);
			return;
		case ID_EDITPAGE:
			SetFocus(g_winData.toolbar.hWndPageEdit);
			SetWindowText( g_winData.toolbar.hWndPageEdit, "" );
			return;

		case ID_INFO:
			if(g_winData.dviwin.pDib)
				DisplayInfo(g_winData.dviwin.pDib);
			else
				MessageNoFile();
			return;

		case ID_INFO_BUFFER:
			ShowBuffer();
			return;

		case ID_INFO_MAP:
			fttInfo();
			return;

		case ID_INFO_FONT:
			if(g_winData.dviwin.pDib)
				ShowInformation();
			else
				MessageNoFile();
			return;

		case ID_INFO_SYS:
			EnvironInfo();
			error(DATATITLE, "System Information");
			return;

		case ID_INFO_PARA:
			ShowParameter();
			return;

		case ID_INFO_PROPW:
			if(!AskYes(
				"Do you really want to perform this function?\n"
				"See newjfm.txt/propw.txt in a package in ./FONT",
				"Output character sizes of TrueType Japanese fonts"))
				return;
			SetPropw(2);
			goto chk_re_open;

		case ID_DIFOPTION:
			error(C_MSG, "%s", PrintAllPara(0));
			error(DATATITLE, "Non-default parameters");
			return;

		case ID_ALLOPTION:
			error(C_MSG, "%s", PrintAllPara(1));
			error(DATATITLE, "All parameters");
			return;

		case ID_OPTION:
			g_bPropertySheetChange = FALSE;
			CreateTabCtrl( g_winData.hMainWnd );
			if(g_bPropertySheetChange == FALSE) return;
			CheckMenu(ID_COLOR, f_spcolor);
			CheckMenu(ID_REPCOLOR, f_rpcolor >= 2 && f_rpcolor != 6);
			tmpname = GetParaString("y");
land:
			CheckMenu(ID_LANDSCAPE,
				tmpname != NULL && *tmpname
				&& tmpname[strlen(tmpname)-1] == 'L');
			goto chk_re_open;

		case ID_PREPARA: /* Choose Parameters... */
			DialogBox(g_winData.hInstance,
				MAKEINTRESOURCE(IDD_READMACRO),
				g_winData.dviwin.hWnd, DlgReadParaProc);
			goto chk_re_open;

		case ID_INSTALL:
			InstallPara();
			break;

		case ID_UNINSTALL:
		  {
			static char *reg_key[] = {
				"FILE", "FIND", "KeyTable", "Settings"
			};
			if(MessageBox(g_winData.hMainWnd,
				"Delete all data in registry created by dviout\n"
				"and quit dviout (cf. Help->Help Topics->Uninstall).",
				"Warning",
				MB_OKCANCEL|MB_DEFBUTTON2|MB_ICONEXCLAMATION)
					== IDOK
			 && MessageBox(g_winData.hMainWnd,
				"Do you really want to uninstall dviout?",
				"Warning",
				MB_OKCANCEL|MB_DEFBUTTON2|MB_ICONEXCLAMATION)
					== IDOK){
				if((tmpname = getenv("TMP")) != NULL ||
				   (tmpname = getenv("TEMP")) != NULL){
				   strcpy(common_work, tmpname);
				   tmpname = common_work + strlen(common_work);
				   if(tmpname == common_work || *(tmpname-1) != '\\')
					*tmpname++ = '\\';
					strcpy(tmpname, "DVITMP.BAT");
					unlink(common_work);
					strcpy(tmpname, "DVITMP.PAR");
					unlink(common_work);
					strcpy(tmpname, "GEN_TMP.BAT");
					unlink(common_work);
				}
				// parameters
				strcpy(fname, "Software\\SHIMA\\DVIOUT\\");
				for(temp_page = 0; 
				  temp_page < sizeof(reg_key)/sizeof(char *);
				  temp_page++){
					strcpy(fname+22, reg_key[temp_page]);
					RegDeleteKey(HKEY_CURRENT_USER, fname);
				}
				for(temp_page = 0; temp_page < 10; temp_page++){
					wsprintf(fname+22, "para%c", temp_page + '0');
					RegDeleteKey(HKEY_CURRENT_USER, fname);
				}
				fname[21] = 0;
				RegDeleteKey(HKEY_CURRENT_USER, fname);
				fname[14] = 0;
				RegDeleteKey(HKEY_CURRENT_USER, fname);

	// .dvi
				strcpy(fname, "dvifile\\Shell\\open\\command");
				RestoreClassString(common_work, 0x200, fname, 
					NULL, "");
				tmpname = GetOutPath("exe");
				for(pos = 0; tmpname[pos]; pos++){
					if(tmpname[pos] != common_work[pos])
						goto uninst_skip;
				}
				RegDeleteKey(HKEY_CLASSES_ROOT, fname);
				fname[18] = 0;
				RegDeleteKey(HKEY_CLASSES_ROOT, fname);
				fname[13] = 0;
				RegDeleteKey(HKEY_CLASSES_ROOT, 
					"dvifile\\Defaulticon");
				RegDeleteKey(HKEY_CLASSES_ROOT, "dvifile");
				RegDeleteKey(HKEY_CLASSES_ROOT, ".dvi");

uninst_skip:
	// start menu
				if(CallExplorer(START_EXPL, NULL, NULL, NULL)
				  == 0)
					goto uninst_end;
				CallExplorer(DELETE_GROUP, "dviout", NULL, NULL);
				CallExplorer(END_EXPL, NULL, NULL, NULL);
uninst_end:
				pos = strlen(tmpname);
				strcpy(tmpname + pos - 3, "gid");
				chmod(tmpname, S_IREAD|S_IWRITE);
				unlink(tmpname);
				strcpy(tmpname + pos - 4, "e.gid");
				chmod(tmpname, S_IREAD|S_IWRITE);
				unlink(tmpname);
				while(--pos > 1){
					if(tmpname[pos] == '\\' || tmpname[pos] == '/')
						break;
				}
				tmpname[pos] = 0;
				sprintf(common_work, 
					"Registry is restored.\n"
					"The holder of dviout is %s\n"
					"Push [Ok] and move the holder to trash box "
					"by explorer if it is unnecessary.",
					tmpname);
				MessageBox(g_winData.hMainWnd, common_work, 
					"Uninstall", MB_OK);
				exit(0);
			}
		  }
			return;

		case ID_MODE_CHANGE:
			DialogBox( g_winData.hInstance,
				MAKEINTRESOURCE(IDD_MODE),
				g_winData.dviwin.hWnd, ModeDlgProc );
			goto chk_re_open;

		case ID_NOMORE_DVIOUT:
			DialogBox( g_winData.hInstance,
				MAKEINTRESOURCE(IDD_NOMORE),
			g_winData.dviwin.hWnd, NoMoreDlgProc );
			return;

		case ID_CHGFONT:
			DialogBox(g_winData.hInstance,
				MAKEINTRESOURCE(IDD_CHGFONT),
				g_winData.dviwin.hWnd, DlgChgFontProc);
			goto chk_re_open;

		case ID_MYHELP:
			WinHelp(g_winData.hMainWnd, "WINHELP32.HLP", 
				HELP_FINDER, 0);
			return;

		case ID_HELP_CONTENTS:
//			WinHelp(g_winData.hMainWnd, GetHelpPath(), 
//				HELP_FINDER, 0);
			HtmlHelp(g_winData.hMainWnd, GetHelpPath(),HH_DISPLAY_TOC, (DWORD)NULL);
			return;

		case ID_FRAME0:
			g_winData.statusbar.bShown = g_winData.slider.bShown
			= g_winData.toolbar.bShown = g_winData.dviwin.bScrollBarShown = 0;
			CheckMenu(ID_STATUS_VIEW, 0);
			CheckMenu(ID_SLIDER_VIEW, 0);
			CheckMenu(ID_TOOLBAR_VIEW, 0);
			CheckMenu(ID_SCROLLBAR_VIEW, 0);
			ResizeAllWindows();
			ShowHyperLink( NULL );
			bShowingHref = FALSE;
			f_quit = 1;
			if(g_winData.dviwin.pDib == NULL)
				break;
			ShowDVI(NULL, NULL);
			return;

		case ID_KSTOP:
			f_kill = !f_kill;
kill:
			CheckMenu(ID_KSTOP, f_kill);
			stop_level = 0;
			if(!f_kill)
				CheckStop(1);
			break;

		case ID_STOPON:
			f_kill = TRUE;
			goto kill;

		case ID_STOPOFF:
			f_kill = FALSE;
			goto kill;

		case ID_DIN:
			f_Din = !f_Din;
Din:
			CheckMenu(ID_DIN, f_Din);
			break;

		case ID_DINON:
			f_Din = TRUE;
			goto Din;

		case ID_DINOFF:
			f_Din = FALSE;
			goto Din;
				
		case ID_STATUS_VIEW:
			toggle = &g_winData.statusbar.bShown;
			goto view_bar;

		case ID_SLIDER_VIEW:
			toggle = &g_winData.slider.bShown;
			goto view_bar;

		case ID_TOOLBAR_VIEW:
			toggle = &g_winData.toolbar.bShown;
view_bar:
			*toggle = !*toggle;
			ResizeAllWindows();
			ShowHyperLink( NULL );
			bShowingHref = FALSE;
			CheckMenu(id, *toggle);
			break;

		case ID_SCROLLBAR_VIEW:
			g_winData.dviwin.bScrollBarShown = !g_winData.dviwin.bScrollBarShown;
			CheckMenu(id, g_winData.dviwin.bScrollBarShown);
			if( g_winData.dviwin.pDib == NULL )
				break;
			ShowDVI(NULL, NULL);
			return;

		case ID_WARNING_VIEW:
			CheckMenu(ID_WARNING_VIEW, view_warning(1));
			break;

		case ID_USELBUTTON:
			g_winData.dviwin.cover_sheet.fButton ^= CS_LBUTTON;
			goto usrrb;

		case ID_USERBUTTON:
			g_winData.dviwin.cover_sheet.fButton ^= CS_RBUTTON;
usrrb:
			CheckMenu(ID_USELBUTTON, g_winData.dviwin.cover_sheet.fButton & CS_LBUTTON);
			CheckMenu(ID_USERBUTTON, g_winData.dviwin.cover_sheet.fButton & CS_RBUTTON );
			break;

		case ID_EDITOR_VIEW:
			ShowPickedString("", "Small Editor");
			break;

		case ID_COVERSUSPEND:		// Presentation mode only
			CoverSuspend();
			break;

		case ID_COVERRETURN:		// Presentation mode only
			if((pos = CoverReturn()) != 0){
				if(f_2page){
					if(IS_2PAGE){
						Clear2Page();
						CheckMenu(ID_DOUBLE, 0);
						CheckMenu(ID_RDOUBLE, 0);
						CheckMenu(ID_VDOUBLE, 0);
					}else{
						AddKeepBMP(0);
						ClearKeepBMP();
					}
					f_2page = 0;
				}
				g_winData.dviwin.cover_sheet.fOn = CS_ON;
				if(pos == 2){
					Initialized_OpenDVI();
					return;
				}
				SaveH_Hist(&g_winData.dviwin, 1);
				pDibNew = nextpage(0);
				RenewDVI( &pDibNew, NULL );
				return;
			}
			break;

		case ID_COVEROFF:
			if(g_winData.dviwin.cover_sheet.fOn){
				CheckMenuSet(id, ID_COVERSHEET, ID_COVERSHEET+2);
				CoverSuspend();		// keep if COVER ON
				g_winData.dviwin.cover_sheet.fOn = CS_OFF;
				if(b_presentation_mode){
					if(g_winData.hWndPresenMenu)
						SendMessage( g_winData.hWndPresenMenu, WM_INITDIALOG, 0, 0 );
					goto chk_re_open;
				}
			}
			break;

		case ID_COVERON:
		case ID_COVERSHEET:
			g_winData.dviwin.cover_sheet.fOn = CS_ON;
			g_winData.dviwin.cover_sheet.bOnForPause = (id == ID_COVERSHEET)?TRUE:FALSE;
			CheckMenuSet(id, ID_COVERSHEET, ID_COVERSHEET+2);
			if(!b_presentation_mode)
				break;
			if(g_winData.dviwin.pDib)
				KeepCover();
			if(!g_winData.dviwin.bHand){
				g_winData.dviwin.bHand = TRUE;
				g_winData.dviwin.loupe.fShape |= F_LHAND;
				SendMessage( g_winData.toolbar.hWndToolBar, 
					TB_CHECKBUTTON, ID_MHAND, MAKELONG(TRUE,0));
			}
			if(!f_2page && g_winData.dviwin.cover_sheet.bOnForPause
			  && !GetCoverPos().x && !GetCoverPos().y ){
				if(GetPause(&xx, &yy, 1) >= 0)
					MoveCover(xx, yy, 1);
				else
					g_winData.dviwin.cover_sheet.bArrangeForPause = TRUE;
			}
			if(g_winData.hWndPresenMenu)
				SendMessage( g_winData.hWndPresenMenu, WM_INITDIALOG, 0, 0 );
			RenewCover();
			g_winData.dviwin.cover_sheet.bArrangeForPause = TRUE;
			goto chk_re_open;

		case ID_SCROL2PAUSE:
			g_winData.dviwin.cover_sheet.bScrollToPause = !g_winData.dviwin.cover_sheet.bScrollToPause;
			CheckMenu(ID_SCROL2PAUSE, g_winData.dviwin.cover_sheet.bScrollToPause);
			break;

		case ID_SEAMLESS:
			f_seamless = !f_seamless;
			CheckMenu(ID_SEAMLESS, f_seamless);
			break;

		case ID_PAINTON:
			g_winData.dviwin.bStopRedrawByUser = FALSE;
			break;

		case ID_PAINTOFF:
			g_winData.dviwin.bStopRedrawByUser = TRUE;
			break;

		case ID_ENGLISH_HELP:
			f_English = !f_English;
			CheckMenu(ID_ENGLISH_HELP, f_English);
			break;

		case ID_TROUBLE_HELP:
		case ID_TIPS:
			strcpy(common_work, GetOutPath("exe"));
			pos = strlen(common_work);
			while(pos-- > 0 && common_work[pos] != '\\');
			strcpy(common_work+pos+1, 
				id==ID_TROUBLE_HELP?
				"\\DOC\\dvioutQA.html":(f_English?
					"\\DOC\\dviouttipse.html":"\\DOC\\dviouttips.html"));
			ExecHref(hwnd, common_work);
			break;

		case ID_INPUT:
			strcpy(common_work, GetOutPath("exe"));
			xx = pos = strlen(common_work)+1;
			if(texhelp != NULL)
				strcpy(common_work+pos, texhelp);
			else
				common_work[pos] = 0;
					
			if(strlen(common_work+pos) < 4){
				yy = GetSystemMetrics(SM_CXSCREEN);
				sprintf(common_work+pos, 
					"-NULL=(%d,-20)-(%d,746) -dpi=", yy-469, yy+3);
				yy = GetXDpi();
				if(yy%100 == 0){
					sprintf(common_work+0x1000,
						"%d -BMP=%d:%d:800",
						yy, yy/100, yy/100);
					strcat(common_work+pos, common_work+0x1000);
				}else
					strcat(common_work+pos, "600 -BMP=6:6:800");
			}
			while(common_work[pos] > 0 && common_work[pos] <= ' ')
				pos++;
			yy = pos;
			if(common_work[pos]){
				while(common_work[pos])
					pos++;
				if(!strcmp(common_work+pos-4, ".dvi")){
					while(common_work[--pos] > ' ' || common_work[pos] < 0);
					pos++;
					SetPath(common_work+pos, common_work+pos);
					goto texhlp;	
				}
				common_work[pos++] = ' ';
			}
			strcpy(common_work+pos, common_work);
			pos += xx-1;
			while(pos-- > 0 && common_work[pos] != '\\');
			strcpy(common_work+pos+1, "HyperTeX\\input.dvi");
texhlp:
			ShellExecute(hwnd, NULL, common_work, common_work+xx,
				NULL, SW_SHOWNORMAL);
			break;

		case ID_GRAPHIC:
			if(!f_graphics){
				f_graphics = f_GS|((f_gbox)?0x1000:0x2000);
				f_GS = 0;
				f_gbox = TRUE;
			}else{
				f_GS = (f_graphics & 0xff);
				if(!(f_graphics & 0x1000))
					f_gbox = FALSE;
				f_graphics = 0;
			}
			CheckMenu(ID_GRAPHIC, !f_graphics);
			goto chk_re_open;

		case ID_COLOR:
			f_spcolor = 1 - f_spcolor;
			CheckMenu(ID_COLOR, f_spcolor);
			goto chk_re_open;

		case ID_REPCOLOR:
			if(f_rpcolor >= 2 && f_rpcolor != 6){
				f_rpold2 = f_rpcolor;
				f_rpcolor = (f_rpold >= 0)?f_rpold:0;
			}else{
				f_rpold = f_rpcolor;
				f_rpcolor = (f_rpold2 >=0)?f_rpold2:2;
			}
			CheckMenu(ID_REPCOLOR, f_rpcolor >= 2 && f_rpcolor!=6);
chk_re_open:
			ReOpen(TRUE);
			return;

		case ID_PENONOFF:
			f_Pen = !f_Pen;
			CheckMenu(ID_PENONOFF, f_Pen);
			break;

		case ID_FLASHLESS:
			f_pDibKeep = !f_pDibKeep;
			CheckMenu(ID_FLASHLESS, f_pDibKeep);
			break;

 // 0x0f Black
 // 0x9f(blue), 0xaf(green),  0xbf(cyan), 0xcf(red), 0xdf(magenta), 0xef(yellow)
		case ID_PENBLACK:
		case ID_PENRED:
		case ID_PENBLUE:
		case ID_PENGREEN:
		case ID_PENMAGENTA:
		case ID_PENCYAN:
		case ID_PENYELLOW:
		case ID_PENWHITE:
			xx = id - ID_PENBLACK;
			PenType &= 0xf;
			if(SetGamma(0) > 0)
				PenType |= xx*0x10+0x80;
			else
				PenType |= (~xx & 0x0f)*0x10;
			CheckMenuSet(id, ID_PENBLACK, ID_PENWHITE);
			break;

		case ID_PENW1:
		case ID_PENW2:
		case ID_PENW3:
		case ID_PENW4:
			PenWidth = id - ID_PENW1;
			if(PenWidth >= 3)
				PenWidth += 2;
			CheckMenuSet(id, ID_PENW1, ID_PENW4);
			break;

		case ID_PENT1:
		case ID_PENT2:
		case ID_PENT3:
		case ID_PENT4:
		case ID_PENT5:
			xx = PenTdata[id - ID_PENT1];
			PenType = (PenType & 0xf0)|xx;
			CheckMenuSet(id, ID_PENT1, ID_PENT5);
			break;
			case ID_PENCLEAR:
			CheckPenBuf();
			ShowDVI(NULL, NULL);
			return;

		case ID_TOOLBAR_CHANGE:
			EnableButton(TRUE);
			SendMessage(g_winData.toolbar.hWndToolBar, TB_ENABLEBUTTON, 
				ID_BNEXTHIST, TRUE);
			SendMessage(g_winData.toolbar.hWndToolBar, TB_ENABLEBUTTON, 
				ID_BGOMARK, TRUE);
			ChangeToolBar(2);
			if( g_winData.dviwin.pDib == NULL ){
				EnableButton(FALSE);
				return;
			}
			ShowDVI(NULL,NULL);
			return;

		case ID_FLAT_SCROLLBAR:
			f_flatscroll = f_flatscroll?FALSE:TRUE;
			MessageCBox( g_winData.dviwin.hWnd, "The style of scroll bar will change\n"
				"when you restart dviout.", "Information", MB_OK );
			CheckMenu(ID_FLAT_SCROLLBAR, f_flatscroll);
			break;

		case ID_PAGEBUTTON:
			f_pagebutton = f_pagebutton?FALSE:TRUE;
			if( f_pagebutton )
				MessageCBox( g_winData.dviwin.hWnd, "The buttons to move page will\n"
				"appear when you restart dviout.", "Information", MB_OK );
			else
				MessageCBox( g_winData.dviwin.hWnd, "The buttons to move page will\n"
				"disappear when you restart dviout.", "Information", MB_OK );
			CheckMenu(ID_PAGEBUTTON, f_flatscroll);
			break;

		case ID_REVERSE_MOVEBUTTON:
			f_rev_movebutton = f_rev_movebutton?FALSE:TRUE;
			CheckMenu(ID_REVERSE_MOVEBUTTON, f_rev_movebutton );
			SetPageMoveButtons( &g_winData.dviwin );
			break;

		case ID_VBACK_DEF:
			pos = -1;
			goto v_back;

		case ID_VBACK_WHITE:
			pos = 0xffffff;
			goto v_back;

		case ID_VBACK_BLACK:
			pos = 0;
v_back:
			ReserveInt("Settings", "ViewBack", pos);
			CheckMenuSet(id, ID_VBACK_DEF, ID_VBACK_BLACK);
			MessageCBox( g_winData.dviwin.hWnd, 
				"Setting of the background will be valid\n"
				"when you restart dviout.", "Information",
				 MB_OK );
			break;

		case ID_WHITEDEF:
		case ID_BLACKDEF:
		case ID_DEFDEF:
		case ID_BLACKBACK:
		case ID_WHITEBACK:
			f_background = id - ID_WHITEDEF;
			CheckMenuSet(id, ID_WHITEDEF, ID_WHITEBACK);
			break;

		case ID_COVERB:
		case ID_COVERR:
		case ID_COVERL:
		case ID_COVERBR:
		case ID_COVERBL:
			xx = id - ID_COVERB;
			switch(xx){
				case 0:
					g_winData.dviwin.cover_sheet.fPlace = CS_BOTTOM;
					break;
				case 1:
					g_winData.dviwin.cover_sheet.fPlace = CS_RIGHT;
					break;
				case 2:
					g_winData.dviwin.cover_sheet.fPlace = CS_LEFT;
					break;
				case 3:
					g_winData.dviwin.cover_sheet.fPlace = CS_BOTTOM | CS_RIGHT;
					break;
				case 4:
					g_winData.dviwin.cover_sheet.fPlace = CS_BOTTOM | CS_LEFT;
					break;
			}
			CheckMenuSet(id, ID_COVERB, ID_COVERB+4);
			break;

		case ID_INF_LARGE:
			inf_size = 4 ;
			goto check_inf_size;
		case ID_INF_MEDIUM:
			inf_size = 2;
			goto check_inf_size;
		case ID_INF_SMALL:
			inf_size = 1;
check_inf_size:
			CheckMenuSet(id, ID_INF_LARGE, ID_INF_SMALL);
			g_cyShowMessage = MINI_INFO*inf_size;
			ResizeAllWindows();
			break;

		case ID_ABOUTB:
			if((id=GetUserKey(0)) == 0)
				id = ID_DVIPRT;
			goto wmcmd;

		case ID_ABOUT:
			DialogBox( g_winData.hInstance, 
					MAKEINTRESOURCE(IDD_ABOUTDIALOG), 
					g_winData.hMainWnd, AboutDlgProc );
			return;

		case ID_LASTFILE:
				if(f_hist_pt > f_hist0 + 1)
				SendMessage(g_winData.dviwin.hWnd, WM_USER_HISTORY_OPEN, 
					MAKEWPARAM(f_hist_pt - 2, TRUE), 0L);
			return;

		case ID_F_HISTORY:
			if(f_hist_pt <= f_hist0)
				return;
			goto diaghis;

		case ID_P_HISTORY:
			if(g_winData.dviwin.pDib){
diaghis:
				SetIdHist( id );
				f_hist_msg = F_HM_HISTORY;
				SaveH_Hist(&g_winData.dviwin, 1);
				DialogBox( g_winData.hInstance, 
					MAKEINTRESOURCE(IDD_HISTORYDIALOG),
					hwnd, DlgHFunct);
			}
			return;

		case ID_FMENU1:
		case ID_FMENU2:
		case ID_FMENU3:
		case ID_FMENU4:
		case ID_FMENU5:
		case ID_FMENU6:
		case ID_FMENU7:
		case ID_FMENU8:
		case ID_FMENU9:
			pos = id - ID_FMENU1;
			if(!f_fmenu[pos].name) return;
			if(		HIBYTE(GetKeyState(VK_SHIFT))
				&& !HIBYTE(GetKeyState(VK_CONTROL)) ){
				strncpy(fname, f_fmenu[pos].name+3, MAX_PATH);
				size = strlen(fname);
				while(size && fname[size] != '\\' && 
				  fname[size] != ':')
					size--;		// cut the file name
				if(size){
					fname[size+1] = 0;
					size = GetFileAttributes(fname);
					if(size != 0xffffffff
					  && (size & FILE_ATTRIBUTE_DIRECTORY)
					  && QueryFileName(fname))
						goto opendvi0;
					return;
				}
			}
			if(strcmp(current_name, f_fmenu[pos].name+3) || !g_winData.dviwin.pDib){
				if(access(f_fmenu[pos].name+3, 0)){
					error(WARNING, "Cannot find %s", 
						f_fmenu[pos].name+3);
					return;
				}
				DefineDVIFileName( f_fmenu[pos].name+3 );
				if(!HIBYTE(GetKeyState(VK_CONTROL)))
					SetStartPage(f_fmenu[pos].page);
				else
opendvi0:
					if(HIBYTE(GetKeyState(VK_SHIFT)))
						SetStartPage(30000);
				SetColor(4);
				Initialized_OpenDVI();
				return;
			}
			if(!(temp_page = f_fmenu[pos].page-GetCurrentPage())) return;
			ShowNewPage(temp_page);
			return;

		case ID_SCRUP:
			SendMessage( hwnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP,0), 0 );
			return;

		case ID_SCRDW:
			SendMessage( hwnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN,0), 0 );
			return;

		case ID_SCRLF:
			SendMessage( hwnd, WM_HSCROLL, MAKEWPARAM(SB_LINEUP,0), 0 );
			return;

		case ID_SCRRT:
			SendMessage( hwnd, WM_HSCROLL, MAKEWPARAM(SB_LINEDOWN,0), 0 );
			return;

		case ID_FILEOPEN:
			if( !QueryFileName(NULL) ) return;
			SetColor(4);
			NewOpen();
			return;

		case ID_SAVECLIPBMP:
		case ID_SAVECLIPWMF:
			if(g_winData.dviwin.pDib == NULL) return;
/*
			if(RectCut(0)){
				pos = AskYes(
					"Save indicated Region (Yes)?\n"
					"No -> the current whole sheet",
					(id == ID_SAVECLIPBMP)?
					"Copy to Clipboard as BMP":
					"Copy to Clipboard as EMF");
			}else
				pos = 0;
*/
			pos = RectCut(0)?1:0;
			tmpname = NULL;
			xx = ((BITMAPINFOHEADER*)g_winData.dviwin.pDib)->biBitCount;
			if(id == ID_SAVECLIPBMP)
				goto clipbmp;
			goto clipemf;

		case ID_SAVEIMG:
			if(g_winData.dviwin.pDib == NULL) return;
			if(RectCut(0)){
				pos = AskYes(
					"Save indicated Region (Yes)?\n"
					"No -> the current whole sheet",
					"Save as a image file(BMP/EMF/BMC/PNG/PDF/EPS etc.)");
			}else
				pos = 0;
			if((tmpname = QuerySaveName()) != NULL ){
				char *ext;

				size = strlen(tmpname);
				for(ext = NULL, xx = 1; xx < 5 && xx < size; xx++){
					if(tmpname[size - xx] == '.'){
						ext = tmpname + size - xx;
						break;
					}
				}
				if(ext == NULL){
					strcat(tmpname + size, ".bmp");
					ext = tmpname+size;
					size += 4;
				}
				xx = ((BITMAPINFOHEADER*)g_winData.dviwin.pDib)->biBitCount;

	/* EMF output */
				if( !stricmp(ext, ".emf") ){
clipemf:
					if(pos){
						href = MareaPara("y OX OY", 1);
						RectCut(1);
						ReplaceBmp(&g_winData.dviwin, MakeBMP());
					}
					error(C_MSG, "%s: %d x %d pixel (%d bits)", 
						(tmpname==NULL)?"clipboad":tmpname, 
						GetDibWidth(g_winData.dviwin.pDib), GetDibHeight(g_winData.dviwin.pDib), xx);
					error(DATATITLE, "Save as a emf file");
					Page2EMF(tmpname);
					if(!pos){
						ReOpen(FALSE);
						return;
					}
rect_recv:
					href = MareaPara(href, -1);
rect_rec2:
					ExpandPage();
					pDibNew = MakeBMP();
					RenewDVI( &pDibNew, NULL );
					return;
				}
	/* general format except for emf/bmp/bmc */
				if(*ext && ext[1]
				  && stricmp(ext, ".bmp") && stricmp(ext, ".bmc") ){
					sprintf(common_work, "^x\\utility\\dvi$%s.bat", ext+1);
					if(my_access(common_work, 0) != FAILURE){
						SaveImage(pos, tmpname);
						return;
					}
		/* ask A-B converter */
					yy = open_xplugin(ext, xx);
					if(yy && yy <= 8){
						unsigned char *Binfo, *Bdata;
						int Sdata, Ssize;

						if(xx != yy){
							if(xx = 1)
								yy = 8;
							SetColor(yy);
						}
						if(pos || xx != yy){
							if(pos){
								href = MareaPara("y OX OY sdpi", 1);
								RectCut(1);
							}
							SetParaInt("sdpi", GetXDpi()*2);
							pDibNew = MakeBMP();
						}
						else
							pDibNew = g_winData.dviwin.pDib-sizeof(BITMAPFILEHEADER);
			/* require memory blocks */
						Ssize=((BITMAPFILEHEADER*)pDibNew)->bfSize;
						Sdata=((BITMAPFILEHEADER*)pDibNew)->bfOffBits;
						Binfo = (char*)marea(Sdata-sizeof(BITMAPFILEHEADER));
						memcpy(Binfo, pDibNew+sizeof(BITMAPFILEHEADER),
							Sdata - sizeof(BITMAPFILEHEADER));
						Bdata = (pos || xx != yy)?
								pDibNew:(char*)marea(Ssize - Sdata);
						memmove(Bdata, pDibNew + Sdata, Ssize - Sdata);

		/* use A-B converter */
						inf_size = SavePicture(tmpname, Binfo, Bdata, 
							GetDibWidth(Binfo), GetDibHeight(Binfo),
						yy, "Created by dviout");

						open_xplugin(NULL, 0);

						if(xx != yy)
							SetColor(xx);
						error(C_MSG, "%s: %d x %d pixel (%d bits)", 
							tmpname, 
							GetDibWidth(Binfo), GetDibHeight(Binfo),
							yy);
						Free0(Binfo);
						Free0(Bdata);
							error(DATATITLE, "%save as a %s file", 
							inf_size?"Cannot s":"S",
							ext + 1);
						ToDviDir();
						if(pos)
							goto rect_recv;
						if(xx != yy)
							goto rect_rec2;
						return;
					}
					if(yy){
						open_xplugin(NULL, 0);
						error(WARNING, "Cannot save as a %s file"
							"(color bits %d)", ext+1, yy);
					}else
						error(WARNING, "Cannot save as a %s file"
							"(No plug-in: ex%s.xpi)", ext+1, ext+1);
					return;
				}
/* bmp/bmc format */
				if( (fp = fopenf(tmpname, "wb")) != NULL ){
clipbmp:
					if(pos){
						href = MareaPara("y OX OY", 1);
						RectCut(1);
						ReplaceBmp(&g_winData.dviwin, MakeBMP());
					}
					error(C_MSG, "%s: %d x %d pixel (%d bits)", 
						(tmpname==NULL)?"clipboad":tmpname, 
						GetDibWidth(g_winData.dviwin.pDib), GetDibHeight(g_winData.dviwin.pDib), xx);
					if(tmpname == NULL){
						unsigned char *Bdata;
							pDibNew = g_winData.dviwin.pDib-sizeof(BITMAPFILEHEADER);
						xx =((BITMAPFILEHEADER*)pDibNew)->bfSize -sizeof(BITMAPFILEHEADER);
						Bdata = (char*)marea(xx);
						memmove(Bdata, g_winData.dviwin.pDib, xx);
						OpenClipboard(g_winData.hMainWnd);
						EmptyClipboard();
						SetClipboardData(CF_DIB, GlobalHandle(Bdata));
						CloseClipboard();
						Free(Bdata);
					}else if(!stricmp(ext, ".bmc")){
						tmpname[size-1] = 'p';
						fclose(fp);
						bmp2bmc(tmpname,
(unsigned char*)g_winData.dviwin.pDib - sizeof(BITMAPFILEHEADER),
((BITMAPFILEHEADER *)((char*)g_winData.dviwin.pDib-sizeof(BITMAPFILEHEADER)))->bfSize);
						tmpname = "BMC";
					}else{
						fwrite((char*)g_winData.dviwin.pDib-sizeof(BITMAPFILEHEADER),
((BITMAPFILEHEADER *)((char*)g_winData.dviwin.pDib-sizeof(BITMAPFILEHEADER)))->bfSize,
						1, fp);
						fclose(fp);
						tmpname = "BMP";
					}
					ToDviDir();
					if(tmpname==NULL)
						error(DATATITLE, "Saved in Clipboard");
					else
						error(DATATITLE, "Saved as a %s file", tmpname);
					if(pos)
						goto rect_recv;
				}else
					error(WARNING, "Cannot open %s", tmpname);
			}
			return;

		case ID_READOPTION:
			if((tmpname = QueryParaName()) == NULL) return;
			pos = GetNamePos(tmpname);
			pos = ( tmpname[pos] ==  '$' && tmpname[pos+1] == '_')?
				0x1000:0;
			pos |= CheckParaFile(tmpname, NULL);
			pos = MessageCBox( g_winData.hMainWnd, 
				  common_work, tmpname, (pos&0x1000)?
					MB_YESNOCANCEL:MB_OKCANCEL);
			if(pos == IDYES)
				Install2Reg(tmpname);
			else if(pos == IDNO || pos == IDOK)
				set_config(tmpname);
			else
				pos = -1;
			if( g_winData.dviwin.pDib != NULL ){
				ToDviDir();
				if(pos != -1){
					ReOpen(FALSE);
					return;
				}
			}
			return;

		case ID_INFO_KEY:
			DisplayKeyInfo();
			return;

		case ID_INFO_URL:
			DisplayURL();
			return;

		case ID_INFO_ANCHOR:
			DisplayAnchor(g_winData.dviwin.pDib);
			return;

		case ID_INFO_SRC:
			DisplaySRC(g_winData.dviwin.pDib);
			return;

		case ID_INFO_ETF:
			DisplayETF();
			return;

		case ID_INFO_INIT:
			size = GetAddMemory("initial.par", NULL, 0);
			if(size > 0){
				tmpname = (char*)marea(size+1);
				GetAddMemory("initial.par", tmpname, size);
				tmpname[size] = 0;
				error(C_MSG, "%s", tmpname);
				Free(tmpname);
				error(DATATITLE, "initial.par");
			}
			break;

		case ID_RESTOREKEY:
			RestoreBinary( key_table, MAX_KEYDEF, 
				"KeyTable", "Key", 0 );
			return;

		case ID_SAVEKEY:
			ReserveBinary( "KeyTable", "Key", key_table, MAX_KEYDEF );
			return;

		case ID_TIMER:
			f_timer = !f_timer;
			CheckMenu(ID_TIMER, f_timer);
			if(f_timer)
				SetTimer(g_winData.hMainWnd, 9, 500, (TIMERPROC)Timer9Proc);
			else
				KillTimer(g_winData.hMainWnd, 9);
			break;

		case ID_MACRO1:
		case ID_MACRO2:
		case ID_MACRO3:
		case ID_MACRO4:
		case ID_MACRO5:
			if(f_macro || key_macro == NULL) return;
			id -= ID_MACRO1;
						/* search id-th paramater */
			for(tmpname = key_macro; id-- > 0; ){
				if(*tmpname++ == '"'){
					while(*tmpname !=  '"'){
						if(!*tmpname++) return;
					}
					tmpname++;
				}else
					while((unsigned char)*tmpname > ' ')
						tmpname++;
				while((unsigned char)*tmpname <= ' '){
					if(!*tmpname++) return;
				}
			}

			if(*tmpname == '"'){
				tmpname++;
				pos = 1;
			}else
				pos = 0;
			while((unsigned char)*tmpname <= ' ' && *tmpname)
				tmpname++;
			for(size = 0; *tmpname; ){
				if(pos){
					if(*tmpname == '"')
						break;
				}else if((unsigned char)*tmpname <= ' ')
					break;
				common_work[size++] = *tmpname++;
			}
			common_work[size] = 0;
			DoMacro(common_work, KEY);
			return;

		case ID_INITIALIZE:
			if( f_Expand )
				goto chk_re_open;
			return;

		case ID_BACKGROUND:
			if(b_presentation_mode){
				size = GetBackGround();
				if(pr_color != (COLORREF)size){
					pr_color = (COLORREF)size;
					pos = COLOR_APPWORKSPACE;
					SetSysColors(1, &pos, &pr_color);
				}
			}
			return;

		case ID_BREOPEN:
			if((id = GetUserKey(1)) != 0)
				goto wmcmd;

		case ID_REOPEN:
			ResetFile();
			if(!IS_MPAGE && (f_killstop = f_kill) == FALSE){
				stop_level = 0;
				CheckStop(1);
			}
			id_current_macro = 0;	// Re expand dviout specials

		case ID_REOPENMACRO:
			ReOpen(FALSE);
			return;

#ifdef	USE_ETF
		case ID_ETF:
			if(g_winData.dviwin.pDib){
				pos = DialogBox( g_winData.hInstance, 
					MAKEINTRESOURCE(IDD_INITETF), hwnd, DlgInitETF);
				temp_page = GetCurrentPage();
				if(pos == IDC_ETFDEL) DeleteETF(0);
				else if(pos == IDC_ETFSTRIP) DeleteETF(1);
				else if(pos != IDOK || !MakeETF()) return;
				SetStartPage(temp_page);
				NewOpen();
				return;
			}
			return;
#endif
		case ID_DVIPRT:
			g_bPrintingByDVIPRT = TRUE;
		case ID_PRINT:
			if( g_winData.dviwin.pDib == NULL || b_presentation_mode)
			{	/* もし g_winData.dviwin.pDib == NULL, i.e. 何も表示されていないなら
			   メッセージを表示して抜ける */
				ShowMessage("Not opened dvi file.", NULL, 
					SM_OKCONT);
				g_bPrintingByDVIPRT = FALSE;
				return;
			}
			pos = f_hyper;
			f_hyper &= ~1;
			size = SetColor(0);
			SetColor(4);
			PrintBmp( g_winData.dviwin.pDib );
			g_bPrintingByDVIPRT = FALSE;
			SetColor(size);
			f_hyper = pos;
			if(f_dstop){
				f_dstop = 0;
				ShowDVI(NULL,NULL);
				return;
			}
			return;

		case ID_SEARCH:
			if(!f_2page)
			{
				if(g_winData.hWndFind != NULL)
					break;
				if(g_winData.dviwin.pDib == NULL){
					MessageNoFile();
					return;
				}
				g_winData.hWndFind = FindText(&find_replace);
			}
			return;
			
		case ID_PRECAND:
			SetUpSearchFromCombo( &find_replace );
			if( g_winData.dviwin.pDib == NULL || !IsSetSearchStr() || szFind[0] == 0)
				break;
			if((href = Search2Href(find_replace.lpstrFindWhat)) != NULL){
				ExecuteHyperReference( href );
				return;
			}
			find_replace.Flags &= ~FR_DOWN;
sstr:
			SaveHistoryAndSearchStr();
			return;

		case ID_NEXTCAND:
			if( g_winData.dviwin.pDib == NULL)
				break;
			SetUpSearchFromCombo( &find_replace );
			if( g_winData.dviwin.pDib == NULL || !IsSetSearchStr() || szFind[0] == 0)
				break;
			if((href = Search2Href(find_replace.lpstrFindWhat)) != NULL){
				ExecuteHyperReference( href );
				return;
			}
			find_replace.Flags |= FR_DOWN; 
			SaveHistoryAndSearchStr();
			return;

		case ID_QUIT:
			f_quit = 1;

		case ID_APPEXIT:
			if(b_presentation_mode){
				pos = COLOR_APPWORKSPACE;
				SetSysColors( 1, &pos, &wbk_color );
				f_quit = 1;
			}
			PostMessage( g_winData.hMainWnd, WM_DESTROY, 0, 0 );
			return;

		case ID_HYPERTEX:
			f_hypertex = !f_hypertex;
			CheckMenu(ID_HYPERTEX, f_hypertex);
			break;

		case ID_HYPER:
			if(f_2page) return;
			f_hyper ^= F_H_IGNORE;
			pos = !(f_hyper & F_H_IGNORE)?TRUE:FALSE;
			SendMessage( g_winData.toolbar.hWndToolBar, TB_CHECKBUTTON,
				ID_HYPER, MAKELONG(pos,0) );
			EnableMenuItem( g_winData.hMenu, ID_HYPERTEX, 
				pos?MF_ENABLED:MF_GRAYED );
			EnableMenuItem( g_winData.hMenu, ID_SRCSPECIAL, 
				pos?MF_ENABLED:MF_GRAYED );
			if(g_winData.dviwin.pDib == NULL)
				break;
			if(!(f_hyper & F_H_IGNORE) && !IsHyperTag())
				ExpandPage();	// On HyperJump && not yet exapanded
			pDibNew = MakeBMP();
			RenewDVI( &pDibNew, NULL );
			return;

		case ID_LOGOPEN:
			g_bLog = (g_bLog == TRUE)?FALSE:TRUE;
			CheckMenu(ID_LOGOPEN, g_bLog);
			break;

		case ID_HEADFOOT:
			if(!g_winData.dviwin.nVscrollPos){
				UpPage();
				return;
			}
			SendMessage( g_winData.dviwin.hWnd, WM_VSCROLL,
				MAKEWPARAM( SB_PAGEUP, 0 ), (LPARAM)g_winData.dviwin.hWnd );
			break;

		case ID_PAGEHEAD:						
			SendMessage( g_winData.dviwin.hWnd, WM_VSCROLL,
				MAKEWPARAM( SB_TOP, 0 ), (LPARAM)g_winData.dviwin.hWnd );
				break;

		case ID_FOOTHEAD:
			if(g_winData.dviwin.nVscrollMax <= g_winData.dviwin.nVscrollPos){
				DownPage();
				return;
			}
			SendMessage( g_winData.dviwin.hWnd, WM_VSCROLL,
				MAKEWPARAM( SB_PAGEDOWN, 0 ), (LPARAM)g_winData.dviwin.hWnd );
			break;

		case ID_PAGEFOOT:
			SendMessage( g_winData.dviwin.hWnd, WM_VSCROLL,
				MAKEWPARAM( SB_BOTTOM, 0 ), (LPARAM)g_winData.dviwin.hWnd );
					break;

		case ID_LEFTHOME:
			if(g_winData.dviwin.pDib)
				 SendMessage( g_winData.dviwin.hWnd, WM_USER_HSCROLL,
					-g_winData.dviwin.nHscrollPos, 0 );
			break;

		case ID_RIGHTHOME:
			if(g_winData.dviwin.pDib)
				 SendMessage( g_winData.dviwin.hWnd, WM_USER_HSCROLL,
					g_winData.dviwin.nHscrollMax - g_winData.dviwin.nHscrollPos, 0 );
			break;

		case ID_LBIG:
			if(g_winData.dviwin.loupe.diam < 1000)
				g_winData.dviwin.loupe.diam += 50;
			break;

		case ID_LLITTLE:
			if(g_winData.dviwin.loupe.diam >= 60)
				g_winData.dviwin.loupe.diam -= 50;
			else
				g_winData.dviwin.loupe.diam = 10;
			break;

		case ID_LMAGNIFY:
			if(g_winData.dviwin.loupe.div > 1)
				g_winData.dviwin.loupe.div--;
			break;

		case ID_LREDUCE:
			if(g_winData.dviwin.loupe.div < 32)
				g_winData.dviwin.loupe.div++;
			break;

		case ID_LMEASURE:
			g_winData.dviwin.loupe.fShape ^= F_LMEASURE;
			CheckMenu(ID_LMEASURE, g_winData.dviwin.loupe.fShape & F_LMEASURE);
			break;

		case ID_RECTON:
			if(g_winData.dviwin.pDib){
				f_rectcut = !f_rectcut;
				if(f_rectcut){
					rectcut.top = rectcut.left = 0;
					rectcut.right = GetTextXSize();
					rectcut.bottom = GetTextYSize();
				}
				CheckMenu(ID_RECTON, f_rectcut);
				if(!b_presentation_mode){
					ShowDVI(NULL,NULL);
					return;
				}
				else if(g_winData.hWndPresenMenu)
					SendMessage( g_winData.hWndPresenMenu, WM_INITDIALOG, 0, 0 );
			}
			break;

		case ID_RECTCUT:
			if(g_winData.dviwin.pDib && RectCut(0)){
				if(rectcut_org == NULL)
					rectcut_org = MareaPara("y OX OY", 1);
				RectCut(1);
new_rec:
				pDibNew = MakeBMP();
				rectcut.top = rectcut.left = 0;
				rectcut.right = GetTextXSize();
				rectcut.bottom = GetTextYSize();
				RenewDVI( &pDibNew, NULL );
				return;
			}
			break;

		case ID_RECTREC:
			if(g_winData.dviwin.pDib && rectcut_org != NULL){
				rectcut_org = MareaPara(rectcut_org, -1);
				ExpandPage();
				goto new_rec;
			}
			break;

		case ID_LCURSOR:
			g_winData.dviwin.loupe.bKillCursor = !g_winData.dviwin.loupe.bKillCursor;
			CheckMenu(ID_LCURSOR, g_winData.dviwin.loupe.bKillCursor);
			break;

		case ID_ANIMECURSOR:
			f_animecursor = !f_animecursor;
			CheckMenu(ID_ANIMECURSOR, f_animecursor);
			break;

		case ID_FGRID:
			f_grid =!f_grid;
			CheckMenu(ID_FGRID, f_grid);
			goto new_exp;

		case ID_WGRID:
			DialogBox( g_winData.hInstance,
					MAKEINTRESOURCE(IDD_GRIDSCALEDIALOG),
					g_winData.dviwin.hWnd, GlidScaleDlgProc );
new_exp:
			if(g_winData.dviwin.pDib){
				ExpandPage();
				goto new_rec;
			}
			break;

		case ID_CSHOW:
			f_Wshow = !f_Wshow;
			CheckMenu(ID_CSHOW, f_Wshow);
			break;

		case ID_DIRECTSRC:
			f_directsrc = !f_directsrc;
			CheckMenu(ID_DIRECTSRC, f_directsrc);
			break;

		case ID_GEDIT:
			f_gedit = !f_gedit;
			CheckMenu(ID_GEDIT, f_gedit);
			break;

		case ID_CHKCOLOR:
			g_bCheckColorSpecial = !g_bCheckColorSpecial;
			CheckMenu(ID_CHKCOLOR, g_bCheckColorSpecial);
			break;

		case ID_LANDSCAPE:
			tmpname = GetParaString("y");
			if(tmpname != NULL && *tmpname){
				strcpy(common_work, tmpname);
				tmpname = common_work + strlen(common_work)-1;
				if(*tmpname == 'L')
					*tmpname = 'P';
				else if(*tmpname == 'P')
					*tmpname = 'L';
set_y:
				SetParaString("y", common_work);
				goto land;
			}else if(paper_type == SIZE_A4){
				tmpname = common_work + 2;
				sprintf(common_work, "A4%c", (f_rotate)?'P':'L');
				goto set_y;
			}
			break;
				
		case ID_PAPER_A3:
		case ID_PAPER_A4:
		case ID_PAPER_A5:
		case ID_PAPER_A6:
		case ID_PAPER_A7:
		case ID_PAPER_B3:
		case ID_PAPER_B4:
		case ID_PAPER_B5:
		case ID_PAPER_B6:
		case ID_PAPER_B3JPN:
		case ID_PAPER_B4JPN:
		case ID_PAPER_B5JPN:
		case ID_PAPER_B6JPN:
		case ID_PAPER_KIKU:
		case ID_PAPER_46:
		case ID_PAPER_NEWBOOK:
		case ID_PAPER_AB:
		case ID_PAPER_LETTER:
		case ID_PAPER_HALFLETTER:
		case ID_PAPER_GOVLETTER:
		case ID_PAPER_LEGAL:
		case ID_PAPER_GOVLEGAL:
		case ID_PAPER_EXECUTIVE:
		case ID_PAPER_POSTCARD:
		case ID_PAPER_SVGA:
		case ID_PAPER_XGA:
		case ID_PAPER_SXGA:
		case ID_PAPER_UVGA:
		case ID_PAPER_USERDEFINED:
		{
			BOOL portrait = TRUE;

			tmpname = GetParaString("y");
			if(tmpname != NULL && *tmpname){
				strcpy(common_work, tmpname);
				tmpname = common_work + strlen(common_work)-1;
				if(*tmpname == 'L')
					portrait = FALSE;
				else if(*tmpname == 'P')
					portrait = TRUE;
			}
			if(id != ID_PAPER_USERDEFINED){
				strcpy( common_work, 
				para_paper[id - ID_PAPER_A3] );
set_PL:
				strcat( common_work, portrait?"P":"L" );
				SetParaString("y", common_work);
				goto chk_re_open;
			}else{
				DialogBox( g_winData.hInstance,
					MAKEINTRESOURCE(IDD_PAPERSIZEDIALOG),
					g_winData.dviwin.hWnd, PaperSizeDlgProc );
				if(*common_work)
					goto set_PL;
			}
		}
		break;

		case ID_MHAND:
			if( g_winData.dviwin.bHand )
			{
				g_winData.dviwin.bHand = FALSE;
				g_winData.dviwin.loupe.fShape &= ~F_LHAND;
				SendMessage( g_winData.toolbar.hWndToolBar, TB_CHECKBUTTON,
						ID_MHAND, MAKELONG(FALSE,0) );
				ChangeMouseCursor(CS_NORMAL);
				ReleaseCapture();
				g_winData.dviwin.bCapture = FALSE;
			}
			else if(g_winData.dviwin.nVscrollMax || g_winData.dviwin.nHscrollMax)
			{
				g_winData.dviwin.bHand = TRUE;
				g_winData.dviwin.loupe.fShape |= F_LHAND;
				SendMessage( g_winData.toolbar.hWndToolBar, TB_CHECKBUTTON,
						ID_MHAND, MAKELONG(TRUE,0) );
			}
			break;

		case ID_DVIOUTSPECIAL:
			f_dvioutspecial = !f_dvioutspecial;
			CheckMenu( ID_DVIOUTSPECIAL, f_dvioutspecial );
			break;

		case ID_SRCSPECIAL:
			f_srcspecial = !f_srcspecial;
			CheckMenu( ID_SRCSPECIAL, f_srcspecial );
			break;
#ifdef	USE_ETF
		case ID_USEETF:
			f_use_etf = !f_use_etf;
			CheckMenu( ID_USEETF, f_use_etf );
			if(g_winData.dviwin.pDib){
				ClearFont();
				ReOpen(FALSE);
				return;
			}
			break;
#endif					
		case ID_SAVEPRESENT:
			DisplayMessage("Save the settings");
			pos = f_pmenu << 4;
			if(!pmenu.top && !pmenu.left)
				pos |= 0x80;
			if(!f_presenmenu)
				pos |= 0x100;
			ReserveInt( "Settings", "Background", pos | f_background );
			pos = g_winData.dviwin.cover_sheet.fPlace;
			if(g_winData.dviwin.cover_sheet.fOn & CS_ON)
				pos |= 0x1000;
			if(g_winData.dviwin.cover_sheet.bOnForPause)
				pos |= 0x2000;
			if(g_winData.dviwin.cover_sheet.bScrollToPause)
				pos |= 0x4000;
			if(!f_dvioutspecial)
				pos |= 0x8000;
			if(!f_srcspecial)
				pos |= 0x10000;
#ifdef	USE_ETF
			if(!f_use_etf)
				pos |= 0x20000;
#endif
			if(!f_hypertex)
				pos |= 0x40000;
			pos |= g_winData.dviwin.cover_sheet.fButton*0x100000;
			ReserveInt( "Settings", "CoverSheet", pos );
			sleep0(500);
			DisplayMessage(NULL);
			break;

		case ID_PRESENMENU:
			f_presenmenu = !f_presenmenu;
			CheckMenu(ID_PRESENMENU, f_presenmenu);
			break;

		case ID_PMLOC:
		{
			RECT pmenu2;
				if(pmenu.top || pmenu.left){
				MoveWindow(g_winData.hWndPresenMenu,
					0, 0,
					pmenu.right - pmenu.left,
					pmenu.bottom - pmenu.top,
					TRUE);
				break;
			}
pmloc:
			GetWindowRect(g_winData.dviwin.hWnd, &pmenu2);
			xx = pmenu.right - pmenu.left;
			yy = pmenu.bottom - pmenu.top;
			switch(f_pmenu){
				case 0:
					xx = xx*53/93;
					yy = yy*41/44;
					break;
				case 1:
					xx = xx*55/93;
					yy = yy*181/185;
					break;
				case 2:
					xx = xx*55/93;
					yy = yy*288/292;
					break;
			}
			MoveWindow(g_winData.hWndPresenMenu,
					pmenupt.x = pmenu2.right - xx,
					pmenupt.y = pmenu2.bottom - yy,
					pmenu.right - pmenu.left,
					pmenu.bottom - pmenu.top, TRUE);
			ShowWindow(g_winData.hWndPresenMenu, SW_SHOW );
//			if(!g_winData.dviwin.bCursorShown){
			if(g_winData.dviwin.fCursorShape == CS_HIDE){
				ShowCursorByMove(TRUE);
			}
			break;
		}

		case ID_SHAPE:
		{
			RECT pmenu2;
				if(g_winData.hWndPresenMenu){
				SendMessage( g_winData.hWndPresenMenu, WM_COMMAND, IDCANCEL, 0 );
				f_pmenu++;
				if( pmenu.left != 0
				 && pmenupt.x == pmenu.left && pmenupt.y == pmenu.top)
					f_pmenu |= 8;
			}
			switch(f_pmenu & 3){
				case 0:
				case 3:
					xx = IDD_PRESEN2;
					f_pmenu &= ~3;
					break;
				case 1:
					xx = IDD_PRESEN1;
					break;
				case 2:
					xx = IDD_PRESEN;
					break;
			}
			g_winData.hWndPresenMenu =
				CreateDialog(g_winData.hInstance,
					MAKEINTRESOURCE(xx),
					g_winData.dviwin.hWnd, DlgPresenProc);
			f_pmshow = TRUE;
			GetWindowRect(g_winData.hWndPresenMenu, &pmenu2);
			MoveWindow(g_winData.hWndPresenMenu,
				pmenu.left, pmenu.top,
				pmenu2.right - pmenu2.left + 1 ,
				pmenu2.bottom - pmenu2.top + 1,
				FALSE);
			GetWindowRect(g_winData.hWndPresenMenu, &pmenu);
			if(f_pmenu & 8){
				f_pmenu &= 3;
				goto pmloc;
			}
			ShowWindow(g_winData.hWndPresenMenu, SW_SHOW );
//			if(!g_winData.dviwin.bCursorShown){
			if(g_winData.dviwin.fCursorShape == CS_HIDE){
				ShowCursorByMove(TRUE);
			}
			break;
		}

		case ID_RELATEDVI:
			RelateDVI();
			break;

		case ID_SETSTARTMENU:
			SetStartMenu();
			break;

		case ID_PRESENTOFF:
			if(b_presentation_mode)
				goto pr_off;
			break;

		case ID_PRESENTON:
			if( b_presentation_mode )
				break;

		case ID_PRESENTATION:
		{
			static BOOL view_StatusBar, view_pageSlider, 
					  view_ToolBar, view_ScrollBar, 
					  org_rectcut, keep_rectcut, f_keep_rect;
			static WINDOWPLACEMENT wpl;
			static int old_loupe;
			static int old_gamma;
			static int old_cmode;
			static int old_OX;
			static int old_OY;
			static BOOL old_f_Pen;
			static save_normal_states = FALSE;
			char c;

			f_killstop = f_kill;
			if( b_presentation_mode )
			{
pr_off:
				ChangeMouseCursor( g_winData.dviwin.bHand?CS_HAND:CS_NORMAL );
				if(g_winData.hWndPresenMenu)
					SendMessage( g_winData.hWndPresenMenu, WM_COMMAND, IDCANCEL, 0 );
				SetForegroundWindow( g_winData.hMainWnd );
				CheckMenu(ID_STATUS_VIEW, 
					g_winData.statusbar.bShown = view_StatusBar);
				CheckMenu(ID_TOOLBAR_VIEW, 
					g_winData.toolbar.bShown = view_ToolBar);
				CheckMenu(ID_SCROLLBAR_VIEW, 
					g_winData.dviwin.bScrollBarShown = view_ScrollBar);
				CheckMenu(ID_SLIDER_VIEW, 
					g_winData.slider.bShown = view_pageSlider);
				keep_rectcut = f_rectcut;
//				CheckMenu(ID_RECTCUT, f_rectcut = org_rectcut);
				f_keep_rect = TRUE;
				pos = COLOR_APPWORKSPACE;
				SetSysColors( 1, &pos, &wbk_color );

				SetWindowLong( g_winData.hMainWnd, GWL_STYLE, wl );
				SetWindowLong( g_winData.dviwin.hWnd, GWL_EXSTYLE, wlc );
				SetMenu( g_winData.hMainWnd, g_winData.hMenu );
				ShowWindow( g_winData.hMainWnd, SW_SHOW );
				SetWindowPlacement( g_winData.hMainWnd, &wpl );
				ShowHyperLink( NULL );
				f_FIT = 0;
				bShowingHref = b_presentation_mode = FALSE;

				save_normal_states = FALSE;
				g_winData.dviwin.loupe.fShape = old_loupe;
				g_winData.dviwin.bHand = (ArrangeScroll(&g_winData.dviwin,0) && 
					(g_winData.dviwin.loupe.fShape & F_LHAND))?FALSE:TRUE;
				SendMessage( g_winData.hMainWnd, WM_COMMAND, ID_MHAND, 0 );
/*
				SetClassLong( g_winData.dviwin.hWnd, GCL_HCURSOR, (LONG)(HCURSOR)NULL );
*/
				ShowCursorByMove(TRUE);
				ResetMouseMoveTimer(-1);

				InitLoupeWindow();
				if(old_OX != OX || old_OY != old_OY){
					ReSetMetric();
					goto set_re_open;
				}
				f_Pen = old_f_Pen;
				if(  old_e != GetParaInt("e")		// changed size
					|| old_varf != GetParaFlag("varf")
					|| old_XGray != GetXGray()
					|| old_YGray != GetYGray()
					|| old_gamma != SetGamma(0)
					|| old_cmode != GetParaInt("cmode")
					|| strcmp(old_y, GetParaString("y")) )
				{
set_re_open:
					SetParaInt("e", old_e);
					SetParaFlag("varf", old_varf);
					SetXYGray(old_XGray, old_YGray);
					c = old_y[max(1,strlen(old_y))-1];
					if( c != 'p' && c != 'P' && c != 'l' && c != 'L' )
						strcat(old_y,"P");
					SetParaString("y", old_y);
					SetGamma(old_gamma);
					SetParaInt("cmode", old_cmode);
					OX = old_OX;
					OY = old_OY;
					CheckView(-1);
					goto chk_re_open;
				}
			} // end of if( b_presen... )
			else
			{
				SetForegroundWindow( g_winData.hMainWnd );
				view_StatusBar = g_winData.statusbar.bShown;
				view_pageSlider = g_winData.slider.bShown;
				view_ToolBar = g_winData.toolbar.bShown;
				view_ScrollBar = g_winData.dviwin.bScrollBarShown;
				g_winData.statusbar.bShown = g_winData.slider.bShown
					= g_winData.toolbar.bShown = g_winData.dviwin.bScrollBarShown = FALSE;
				if( !save_normal_states ){
					old_e = GetParaInt("e");
					old_varf = GetParaFlag("varf");
					if(GetParaString("y") != NULL)
						strncpy(old_y, GetParaString("y"), 0x20);
					else
						strcpy(old_y, "A4P");
					old_XGray = GetXGray();
					old_YGray = GetYGray();
					old_loupe = g_winData.dviwin.loupe.fShape;
					old_gamma = SetGamma(0);
					old_cmode = GetParaInt("cmode");
					org_rectcut = f_rectcut;
					old_OX = OX;
					old_OY = OY;
					old_f_Pen = f_Pen;
					save_normal_states = TRUE;
				}
				if(f_keep_rect)
					f_Pen = f_rectcut = keep_rectcut;
				else
					f_Pen = FALSE;
				if(!f_2page)
					SetColor(8);
				if(old_cmode == 0)
					SetParaInt("cmode", 3);
				ShowHyperLink( NULL );
				bShowingHref = FALSE;
				wbk_color = GetSysColor( COLOR_APPWORKSPACE );
				if(f_background & 1)
				{		 			// black
					if(f_background == 1)		// default
						g_winData.dviwin.loupe.fShape = 
							(g_winData.dviwin.loupe.fShape & ~F_LCOLOR)|F_LBLACK;
					size = 0;
				}
				else if(f_background == 2)
				{ 					// default color
					g_winData.dviwin.loupe.fShape &= ~F_LCOLOR;
					size = GetBackGround();
					if(size != 0xffffff)
						g_winData.dviwin.loupe.fShape = 
							(g_winData.dviwin.loupe.fShape & ~F_LCOLOR)|F_LBLACK;
				}
				else
				{					// white
					if(f_background == 0)		// white
						g_winData.dviwin.loupe.fShape &= ~F_LCOLOR;
					size = 0xffffff;
				}
				pos = COLOR_APPWORKSPACE;
				SetSysColors(1, &pos, &size);
					wl = GetWindowLong(g_winData.hMainWnd, GWL_STYLE);
				wlc = GetWindowLong(g_winData.dviwin.hWnd, GWL_EXSTYLE);
				wpl.length = sizeof(WINDOWPLACEMENT);
				GetWindowPlacement( g_winData.hMainWnd, &wpl );
				SetMenu( g_winData.hMainWnd, NULL );
				SetWindowLong( g_winData.hMainWnd, GWL_STYLE, 
					wl & ~WS_OVERLAPPEDWINDOW );
				SetWindowLong( g_winData.dviwin.hWnd, GWL_EXSTYLE, 
					wlc & ~WS_EX_CLIENTEDGE );
				ShowWindow( g_winData.hMainWnd, SW_NORMAL );
				ShowWindow( g_winData.hMainWnd, SW_MAXIMIZE );
				ShowCursorByMove(FALSE);
				ResetMouseMoveTimer(0);
				b_presentation_mode = TRUE;
				InitLoupeWindow();
/*
				SetClassLong( g_winData.dviwin.hWnd, GCL_HCURSOR, 
					(g_winData.dviwin.loupe.fShape&F_LHAND)?(LONG)g_winData.pCursor[CS_LASER_HAND]:(LONG)g_winData.pCursor[CS_POINTER] );
*/
				if(g_winData.dviwin.cover_sheet.fOn == CS_ON)
				{
					if(g_winData.dviwin.pDib) KeepCover();
					if(!g_winData.dviwin.bHand)
					{
						g_winData.dviwin.bHand = TRUE;
						g_winData.dviwin.loupe.fShape |= F_LHAND;
						SendMessage( g_winData.toolbar.hWndToolBar, 
							TB_CHECKBUTTON, ID_MHAND, MAKELONG(TRUE,0));
					}
					if(!f_2page && g_winData.dviwin.cover_sheet.bOnForPause
						&& !GetCoverPos().x && !GetCoverPos().y )
					{
						if(GetPause(&xx, &yy, 1) >= 0)
							MoveCover(xx, yy, 1);
						else
							g_winData.dviwin.cover_sheet.bArrangeForPause = TRUE;
					}
				}
				if(f_presenmenu && g_winData.hWndPresenMenu == NULL)
					PostMessage( g_winData.hMainWnd, WM_COMMAND, ID_SHAPE, 0 );
				if(f_background == 0)
				{
					if(SetGamma(0) < 0)
						goto to_reverse;
				}
				else if(f_background == 1 && SetGamma(0) > 0)
					goto to_reverse;
				if(g_winData.dviwin.pDib){
					ShowDVI(NULL, NULL);
					return;
				}
			} // end of if(b_presentation_mode)
			break;
		} // end of case ID_PRESENTATION:

		case ID_AUTO_SAVE_IMAGE:
			if( !autosavebmp.f_autosavebmp ){
				if( DialogBox(g_winData.hInstance, MAKEINTRESOURCE(IDD_AUTOSAVE_IMG),
					g_winData.dviwin.hWnd, AutoSaveDlgProc) == IDOK ){
					CheckMenu( ID_AUTO_SAVE_IMAGE, TRUE );
					autosavebmp.f_autosavebmp = TRUE;
				}
			}
			else{
				CheckMenu( ID_AUTO_SAVE_IMAGE, FALSE );
				autosavebmp.f_autosavebmp = FALSE;
			}
			break;	
	} // end of WM_COMMAND
}
