/* R A R E M S G . C */


#ifdef DEBUG
#ifdef PCJ
/* #define SHOWYIELDWAITMSG */
#endif /* PCJ */
#endif /* DEBUG */

#define NOKEYSTATE
#define NOICON
#define NOBRUSH
#define NOCREATESTRUCT
#define NODRAWTEXT
#define NOMETAFILE
#define NOMINMAX
#define NOPEN
#define NOREGION
#define NOSOUND
#define NOTEXTMETRIC
#define NOWNDCLASS
#define NOCOMM
#include "word.h"
DEBUGASSERTSZ            /* WIN - bogus macro for assert string */
#include "heap.h"
#define NOIFK
#define USEBCM
#include "opuscmd.h"
#include "keys.h"
#include "doc.h"
#include "disp.h"
#include "props.h"
#include "sel.h"
#include "screen.h"
#include "print.h"
#include "ch.h"
#include "format.h"
#include "status.h"
#include "wininfo.h"
#include "menu2.h"
#include "dde.h"
#include "helpapi.h"
#include "help.h"
#include "debug.h"
#include "field.h"
#include "cmdtbl.h"
#include "sdmver.h"
#include "sdm.h"
#include "core.h"
#include "idle.h"
#include "message.h"
#include "rareflag.h"
#include "file.h"
#include "doslib.h"
#include "layout.h"
#include "preview.h"
#include "error.h"
#include "prompt.h"

#define MPILCDBCM
#include "cmdlook.h"

extern BOOL             vfDdeIdle;
extern BOOL             vfRecording;
extern FARPROC          vlppFWHChain;
extern int              vfInitializing;
extern struct MWD       **hmwdCur;
extern int              vlm;
extern HANDLE  vhInstance;
extern HWND  vhwndApp;
extern HWND  vhwndDeskTop;
extern HMENU vhMenu;
extern BOOL  vfInitializing;
extern struct WWD       **hwwdCur;
extern int              wwCur;
extern struct WWD       **mpwwhwwd[];
extern struct MWD       **hmwdCur;
extern int              mwCur;
extern struct MWD       **mpmwhmwd[];
extern struct STTB      **vhsttbWnd;
extern struct SCI  vsci;
extern struct SEL  selCur;
extern struct PREF vpref;
extern struct FTI  vfti;
extern struct LCB  vlcb;
extern struct CA caPage;
extern struct CA caPara;
extern struct FLI vfli;
extern int wwCur;
extern BOOL vfOvertypeMode;
extern BOOL vfExtendSel;
extern BOOL vfBlockSel;
extern struct MERR vmerr;
extern char szClsStatLine[];
extern struct RC        vrcUnZoom;
extern int              mwCur;
extern int              mwMac; /* mac of child window */
extern int              wwMac;
extern int              wwCreating;
extern struct MWD       **mpmwhmwd[];
extern int              docGlobalDot;
extern struct DOD       **mpdochdod[];
extern struct SCI       vsci;
extern struct PRI       vpri;
extern struct FLI       vfli;
extern BOOL             vfWaitForDraw;
extern HWND             vhwndStatLine;
extern HWND             vhwndApp;
extern HWND             vhwndRibbon;
extern HWND             vhwndAppIconBar;
extern HWND             vhwndDeskTop;
extern HWND             vhwndPrompt;
extern HWND             vhwndPgPrvw;
extern struct RC        vrcUnZoom;
extern struct PREF      vpref;
extern HANDLE           vhInstance;
extern HWND             vhwndApp;          /* handle to parent's window */
extern HWND             vhwndDeskTop;
extern HWND             vhwndCBT;
extern HWND             vhwndStatLine;
extern BOOL             vfExtendSel;
extern MSG              vmsgLast;
extern struct WWD       **mpwwhwwd[];
extern struct WWD       **hwwdCur;
extern BOOL             vfInLongOperation;
extern int              wwCur;
extern struct SEL       selCur;
extern struct SEL       selDotted;
extern int              vfDeactByOtherApp;
extern HWND             vhwndMsgBoxParent;
extern IDF		vidf;
extern int              vfSysMenu;
extern int              vssc;
extern struct MERR      vmerr;
extern int              flashID;
extern int              vfFocus;
extern int              vfDoubleClick;
extern HCURSOR          vhcStyWnd;
extern CP               vcpFetch;
extern int              vfSeeSel;
extern char             szApp[];
extern int              docCur;
extern HWND             vhwndAppModalFocus;
extern BOOL		fRecordMove;
extern BOOL		fRecordSize;
extern int              vfLargeFrameEMS;
extern int              vcInMessageBox;
extern int              vfSmallFrameEMS;
extern int              vfUrgentAlloc;
extern PVS		vpvs;
#ifdef OPUS_X64
extern HWND             vhwndWin95Toolbar;
extern int              OpusWin95ChromeActive(void);
extern int              OpusWin95ToolbarHeight(void);
extern void             OpusSizeWin95Toolbar(HWND);
#endif
extern int FAR pascal LbcCmpLbox();
extern WORD				wmWinHelp;
#ifdef WIN23
extern int              vdbmgDevice;
#endif /* WIN23 */

#ifdef BATCH
/* Batch Mode stuff */
BOOL vfBatchMode = fFalse;
CHAR szBatchString[128];
BOOL vfBatchIdle = fFalse;	/* if fTrue, do not exit upon idle in batch mode */
csconst char szOpusRip[] = "opus.rip";


/* %%Function:RipSz %%Owner:TONYKR */
/* Writes a string out to opus.rip */
RipSz(sz)
CHAR *sz;
{
	OFSTRUCT OutReOpenBuff;     /* output file reopen buffer */
	int hFile;

	if (OpenFile((LPSTR) szOpusRip, (OFSTRUCT far *)(&OutReOpenBuff),
			OF_EXIST) == -1)
		{
		hFile = (OpenFile((LPSTR) szOpusRip, (OFSTRUCT far *)(&OutReOpenBuff),
				OF_WRITE | OF_CREATE));
		}
	else
		{
		hFile = (OpenFile((LPSTR) szOpusRip, (OFSTRUCT far *)(&OutReOpenBuff),
				OF_WRITE));
		}
	if (hFile != -1)
		{
		DwSeekDw(hFile, 0, 2);	/* Go to end of file */
		CchWriteDoshnd(hFile, (LPSTR) sz, CchSz(sz) - 1);
		FCloseDoshnd(hFile);
		}
}


/* %%Function:BatchModeError %%Owner:BRADV */
BatchModeError(sz1, sz2, n1, n2)
CHAR *sz1, *sz2;
int n1, n2;
{
	CHAR rgch[256];
	CHAR *pch = rgch;

	DebugBreak(10);

	CchPchToPpch(szBatchString, &pch);
	if (sz1)
		CchPchToPpch(sz1, &pch);
	if (sz2)
		CchPchToPpch(sz2, &pch);
	CchPchToPpch(SzShared(" "), &pch);
	CchIntToPpch(n1, &pch);
	CchPchToPpch(SzShared(", "), &pch);
	CchIntToPpch(n2, &pch);
	*pch = 0;
#ifdef DEBUG
	DoStackTrace(rgch);
#else
	/* If we're not in debug version just write the message to opus.rip */
	*(pch++) = '\r';
	*(pch++) = '\n';
	*pch = '\0';
	RipSz(rgch);
#endif /* DEBUG */
	OurExitWindows();
}


#endif /* BATCH */


/* %%Function:AppWndProcRare %%Owner:chic */
#ifdef OPUS_X64
LRESULT AppWndProcRare(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
#else
long AppWndProcRare(hwnd, message, wParam, lParam)
HWND hwnd;
int message;
WORD wParam;
LONG lParam;
#endif
{
	HDLG hdlg;
	LPPOINT rgpt;

	switch (message)
		{
	default:
		Assert( fFalse );
		break;
	case WM_CREATE:
		/* tell CBT about new window */
		if (vhwndCBT)
			/* this must be the first thing we do under WM_CREATE */
			SendMessage(vhwndCBT, WM_CBTNEWWND, hwnd, 0L);
		vhwndApp = hwnd;
		break;

	case WM_CBTINIT:
		/* CBT sends us this message when it is ready to go */
		vrf.fCbtInit = fTrue;
		return ((LONG) fTrue);

	case WM_SYSTEMERROR:
		if (vrf.fCbtInit)
			break;
		if (wParam == 8)  /* wParam == 8 indicates out of memory */
			SetErrorMat(matMem);
		/* Fall through */

	case WM_CBTTERM:  /* CBT is quitting */
		/* Note: we also get WM_CBTTERM from DOT when it quits; but
				vfr.fRanCBT won't be true in that case */
		if (vhwndCBT != NULL && vrf.fRanCBT)
			{
			/* don't do these in StopCBT because we'll never get there
				(we'll be in the idle loops of dialog or menu */
			EndMenu();  /* end menu mode if we're in it */
			if ((hdlg = HdlgGetCur()) != NULL && FModalDlg(hdlg))
				/* close any open dialog(s) */
				EndDlg(tmcCancel);   /* ok to call EndDlg here */
			/* check for modeless dialog drop-downs open */
			if (HdlgGetFocus() != NULL)
				TermCurIBDlg(fFalse);

			/* postpone rest of CBT cleanup until CbtLib is no longer on
				the stack, since StopCBT does a FreeLibrary of hCbtLib */
			vrf.fMustStopCBT = fTrue;
			}
		else
			{
			vhwndCBT = NULL;
			vrf.fCbtInit = 2;
			}
		return(0L);

	case WM_CBTSEMEV:
		/* if CBT is not installed, we will get this message when
			we send it to ourselves (see below under WM_COMMAND). We
			must return TRUE so normal WM_COMMAND handling occurs */
		return ((LONG) fTrue);

	case WM_SIZE:
			/* Window's size is changing.  lParam contains the height
			** and width, in the high and low words, respectively. */

			{
			static dypApp;

			if (vidf.fIconic = IsIconic(hwnd))
				{
				if (vfInitializing) 
					dypApp = 0; /* make sure we init this */
				break;
				}
	
			if (vfRecording && fRecordSize)
				RecordAppSize(LOWORD(lParam), HIWORD(lParam));

			fRecordMove = fFalse;
			fRecordSize = fFalse;

			if (!vfInitializing || vhwndDeskTop != NULL)
				/* NOTE:  We are guaranteed that dypApp will be set by
					the time it is used here, because the first time
					through this code (at initialization time), the call
					to AppSize won't be made. */
				AppSize(HIWORD(lParam) < dypApp);

			dypApp = HIWORD(lParam);
			break;
			}

	case WM_MOVE:
		EnsureFocusInPane();

		if (vfRecording && fRecordMove)
#ifdef OPUS_X64
			RecordAppMove((short) LOWORD(lParam), (short) HIWORD(lParam));
#else
			RecordAppMove(LOWORD(lParam), HIWORD(lParam));
#endif
		fRecordMove = fFalse;

defproc:    
		return(DefWindowProc(hwnd, message, wParam, lParam));

	case WM_TIMER:
		/* flashID timer event is used to flash the title bar when not
			active.  Other timer events may be used from time to time so
			we must check.
		*/
		if (wParam == flashID)
			{
			Assert (vfDeactByOtherApp);
			FlashWindow(vhwndApp, fTrue);
			}
		break;

	case WM_CLOSE:
		/* The user has selected "Close" on the system menu */
        /* in win3, the tak manager can send this via end task */
		/* Failure to process this message means that DefWindowProc */
		/* Will send us a Destroy message */
		/* A return value of TRUE says " don't close" */
		/* Calling DestroyWindow means "Go ahead and close" */

		/* When Windows sends this message, wParam is 0 (acQuerySave).
			This message might also be posted by the FileExit statement,
				in which case wParam will be the parameter used there. */

		Assert(hwnd == vhwndApp); /* Please tell Brad if this fails... */
		Assert((uns) wParam != acAutoSave);

        if (FCancelClose())
			return (fTrue);

		return !FAppClose(wParam /* ac */ );

	case WM_QUERYENDSESSION:
		{
		extern int vpisPrompt;

		BOOL f;

		/* User has selected "End Session" from the MS-DOS window */
		/* Return TRUE if willing to quit, else return FALSE */

        if (FCancelClose())
			return (fFalse);

		if (vidf.fDead)
			/* we are already shutting down, no need to go through this again */
			return (fTrue);

		vrf.fInQueryEndSession = fTrue;	 /* save dlg needs this */
		f = FQueryEndSession(acQuerySave);
		vrf.fInQueryEndSession = fFalse;   /* in case we don't end */
		if (f)
			{
			WriteUserState();
			return fTrue;
			}
		break;
		}
	case WM_ENDSESSION:
		/* if wParam is TRUE, Windows is shutting down.  This is the
			last message we ever get if the user closes down the session
			from the MSDOS executive. We only have to perform those
			termination actions that could have an effect after Windows
			goes away. */
		/* if wParam is FALSE, then an "End session" has been aborted */
		if (wParam)
			CleanUpForExit();
		break;

	case WM_DESTROY:
		/* Window is being destroyed. */
		AppDestroy();
		return (LONG) TRUE;
	case WM_SYSCOLORCHANGE:
	case WM_WININICHANGE:
	case WM_DEVMODECHANGE:
	case WM_FONTCHANGE:
		AppWinSysChange( message, lParam );
		break;


		/*---------------CLIPBOARD INTERACTION-------------*/

	case WM_RENDERFORMAT:
		/* A request to render the contents of the clipboard
			in the data format specified.  Reception of this message
			implies that the receiver is the current owner of the
			clipboard. See clipbord.c */
		FRenderFormat( wParam );
		break;

	case WM_DESTROYCLIPBOARD:
		/*  A notification that we are about to lose the ownership
			of the clipboard.  We should free any resources that are
			holding the contents of the clipboard */
		DestroyClip();
		break;

		/*-------CLIPBOARD DISPLAY---------------------*/

	case WM_PAINTCLIPBOARD:
		/* A request to paint the clipboard contents.
			wParam is a handle to the clipboard window
			LOWORD( lParam ) is a handle to a PAINTSTRUCT giving
				a DC and RECT for the area to repaint */

           /* could get here while playing a metafile, which would be
              trouble. Invalidate the whole rect so it will be
              painted sometime bz
           */
	    if (vrf.fInDisplayFli)
		    {
            InvalidateRect(wParam, (LPRECT) NULL, fTrue);
            break;
            }
#ifdef OPUS_X64
		PaintClipboard((HWND) wParam, (HANDLE) lParam);
#else
		PaintClipboard( wParam, LOWORD(lParam) );
#endif
		break;

	case WM_VSCROLLCLIPBOARD:
		/* A request to vertically scroll the clipboard contents.
			wParam is a handle to the clipboard window
			LOWORD( lParam ) is the scroll type (SB_)
			HIWORD( lParam ) is the new thumb position (if needed) */

	    if (vrf.fInDisplayFli)
            break;

		VScrollClipboard( wParam, LOWORD(lParam), HIWORD(lParam) );
		break;

	case WM_HSCROLLCLIPBOARD:
		/* A request to horizontally scroll the clipboard contents.
			wParam is a handle to the clipboard window
			LOWORD( lParam ) is the scroll type (SB_)
			HIWORD( lParam ) is the new thumb position (if needed) */

	    if (vrf.fInDisplayFli)
            break;

		HScrollClipboard( wParam, LOWORD(lParam), HIWORD(lParam) );
		break;

	case WM_SIZECLIPBOARD:
		/* A notification that the clipboard window is being re-sized.
			wParam is a handle to the clipboard window
			LOWORD(lParam) is a handle to a RECT giving the new size */

	    if (vrf.fInDisplayFli)
		    break;

#ifdef OPUS_X64
		SizeClipboard((HWND) wParam, (HANDLE) lParam);
#else
		SizeClipboard( wParam, LOWORD(lParam) );
#endif
		break;

	case WM_ASKCBFORMATNAME:
		/* A request for the name of the CF_OWNERDISPLAY clip format.
			wParam is the max. # of chars to store (including terminator)
			lParam is a long pointer to a buffer in which to store the
			name */

		AskCBFormatName( (LPCH) lParam, wParam );
		break;

	case WM_DDE_INITIATE:
		InitiateDde (wParam, LOWORD (lParam), HIWORD (lParam));
		break;

	case WM_NCLBUTTONDBLCLK:
		if (wParam == HTMENU && vfSysMenu)
			{
			POINT pt;
			RECT rc;

			pt = MAKEPOINT(lParam);
			ScreenToClient(hwnd, (LPPOINT) &pt);
			GetWindowRect(hwnd, (LPRECT) &rc);
			ScreenToClient(hwnd, (LPPOINT) &rc);
			rc.top += vsci.dypBdrCapt;
			if (pt.x < vsci.dxpBmpSystem + 2 * vsci.dxpTmWidth && 
					pt.y >= rc.top && pt.y < rc.top + vsci.dypMenuBar)
				{
				CmdExecBcmKc(bcmCloseWnd, kcNil);
				break;
				}
			}
		goto defproc;
		}

	return 0L;
}


/* %%Function:FCancelClose %%Owner:bobz */
/* returns true and puts up a message if we are not prepared to close */
FCancelClose()
{
	    HDLG hdlg;

		/* what we are doing here: we can get into trouble if message boxes
		   or dialogs are up at exit windows time, or we are in an external
           library that can bring up mb or dialogs. If we go ahead and try
		   to close,we get more dialogs and message boxes brought up and in
		   certain cases we will lose track of who is activated. So, to
		   prevent that (and to avoid saving and quitting inthe middle of
		   a replace or spell, for example, we don't allow end session
		   while message boxes or modal dialogs are up.

           Note that we can get into similar problems at wm_close in win3
           with the task manager end task call. In that case we should not
           get the message if we are deactivated, (when a dialog or
           message box is up), but doing all the checks
           should cover us when something changes.
		   
		   bz 9/20/89
		*/

		if (vcInMessageBox || vrf.fInExternalCall ||
			vpisPrompt >= pisAbortCheckMin ||
			vhwndAppModalFocus != NULL ||
			((hdlg = HdlgGetCur()) != hdlgNull && FModalDlg(hdlg)))
			{
            /* must be a system modal message box */
			ErrorEid (eidCantQuitWord, "AppWndProcRare");
			return (fTrue);
			}
        return fFalse;   /* ok to close */
}




/*  NOTE: Messages bound for this WndProc are filtered in wprocn.asm */

/* %%Function:DeskTopWndProc %%Owner:chic */
#ifdef OPUS_X64
LRESULT CALLBACK DeskTopWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
#else
EXPORT long FAR PASCAL DeskTopWndProc(hwnd, message, wParam, lParam)
HWND      hwnd;
unsigned  message;
WORD      wParam;
LONG      lParam;
#endif
{
	Assert (message == WM_SIZE);
	/* no effect to the doc windows inside except if vpref.fZoomMwd */
	if (vpref.fZoomMwd && hmwdCur != hNil)
		DoZoom((*hmwdCur)->hwnd);
	return(0L);
}






/*----------------------------------------------------------------------------
|	WaitActivation
|
|	This routine waits until we are active, while it waits it
|	flashes the title bar to show how impatient it is.
|
|	Arguments:
|		none.
----------------------------------------------------------------------------*/
/* %%Function:WaitActivation %%Owner:chic */
BOOL WaitActivation()
{
	MSG msg;

	Assert(vfDeactByOtherApp);

	if (vidf.fDead || InSendMessage ())
		return;

	Beep();

	SetTimer(vhwndApp, flashID = tidFlash, 500, (LPSTR)NULL);

	while (vfDeactByOtherApp)
		{
		GetMessage((MSG far *)&msg, NULL, 0, 0);
		/* Activated by clicking on our non-client area; don't allow
			menus to drop down */ /* Don't accept command messages unless
			wer're active either... */
		if ((msg.message != WM_COMMAND && msg.message != WM_NCLBUTTONDOWN) || 
				msg.hwnd != vhwndApp)
			{
#ifdef SHOWYIELDWAITMSG
			ShowMsg ("wa", msg.hwnd, msg.message, msg.wParam,
					msg.lParam);
#endif /* SHOWYIELDWAITMSG */
			TranslateMessage((MSG far *)&msg);
			DispatchMessage((MSG far *)&msg);
			}
		}
}



/* %%Function:LoadPreviewFont %%Owner:chic */
LoadPreviewFont()
{
	char *stPrev = StFrame("PREV.FON");
	char szBuffer[cchMaxSz];
	char stFull[ichMaxFile];

	vpvs.fLoadPrvwFon = fFalse;

	if (FFindFileSpec(stPrev, stFull, grpfpiUtil, nfoNormal))
		StToSzInPlace(stFull);
	else
		{
		StToSz(stPrev, stFull);
		/* Avoid "Cannot find PREV.FON" message box if they're not around */
		if (OpenFile((LPSTR)stFull, (LPOFSTRUCT)szBuffer, OF_EXIST) == -1)
			return;
		}
	AddFontResource((LPSTR)stFull);
}

#ifdef WIN23
/* We have two arrays because the vdbmg ordering is different under Win 3 */
/* REVIEW: CGA SIGMA, & 8514 widths */
csconst int mpdbmgTmWidth3[] = {10, 8, 8};
csconst int mpdbmgTmWidth2[] = {10, 8, 8, 8, 8};
#endif /* WIN23 */

/* F  A S S U R E  S D M  I N I T */
/* We postpone initialization of SDM until needed.  Now is the time
	to do it!
*/
/* %%Function:FAssureSdmInit %%Owner:chic */
FAssureSdmInit()
{
	/* Initialize SDM and then unload it... */
	extern FAR pascal sdminit_q();
	extern BOOL FFilterSdmMsg();
	extern HANDLE vhInstance;
	extern HWND vhwndApp, vhwndCBT;
	extern char szClsFedt[];
	extern HCURSOR     vhcArrow;

	BOOL fReturn;
	SDI sdi;

	Scribble(13, 'S');

	sdi.hinstCur = vhInstance;
	sdi.hinstPrev = NULL; /* no prev instances of opus! */
	sdi.strApp = szApp;
	sdi.hwndApp = vhwndApp;
	sdi.pfnFilterMsg = FFilterSdmMsg;
	sdi.strFedtClass = szClsFedt;
	sdi.hcursorArrow = vhcArrow;

	Assert (vsci.hdcScratch != hNil);
	sdi.hdcMem = vsci.hdcScratch;
#ifdef WIN23
	/*
	We want SDM to size based on the width of the old sys font so all our
	dialogs size as they used to. We want to use the height of the Win 3
	sys font if appropriate, since it is bigger than win 2
	*/
	if (vsci.fWin3Visuals)
		sdi.dxSysFontChar =  mpdbmgTmWidth3[vdbmgDevice];  /* Fake Width of system font */
	else if (vsci.fWin3)	/* under win 3, but not new visuals */
		sdi.dxSysFontChar =  mpdbmgTmWidth2[vdbmgDevice];  /* Fake Width of system font */
	else
		sdi.dxSysFontChar =  vsci.dxpTmWidth;  /* Real Width of system font */
	sdi.dySysFontChar =  vsci.dypTmHeight; /* Height of system font */
#else
	sdi.dxSysFontChar =  vsci.dxpTmWidth;  /* Width of system font */
	sdi.dySysFontChar =  vsci.dypTmHeight; /* Height of system font */
#endif /* WIN23 */
	sdi.dySysFontAscent =  vsci.dypTmAscent;
	sdi.szScrollClass = NULL;

	sdi.lpfncomp = LbcCmpLbox;   /* list box compare rtn */
	/* the following two values are new in the sdi structure for
		sdm 2.22 (added for the WIN23 version). */
	sdi.hfont = NULL;
	sdi.dyLeading = vsci.dypTmInternalLeading;

	if (!(fReturn = FInitSdm(&sdi)))
		SetErrorMat(matMem);
	else  if (vhwndCBT)
		CBTState(fTrue);  /* tell SDM that CBT is here */

	if (fReturn)
		ChangeColors(); /* set system colors */

	vmerr.fSdmInit = fReturn; /* we will try again if it failed */

	GlobalLruOldest( GetCodeHandle( (FARPROC)sdminit_q ) );

	Scribble(13, ' ');

	return fReturn;
}






/* %%Function:FRetrySbError %%Owner:chic */
BOOL FRetrySbError(merr, sb, lcbNew, cretry)
int merr;
SB sb;
long lcbNew;
WORD cretry;
{
	return fFalse;
}


/* %%Function:FRetrySdmError %%Owner:chic */
BOOL FRetrySdmError(w, hdlg, sev)
int w;
HDLG hdlg;
SEV sev;
{
	extern int vsasCur;

	if (sev == sevMinor)
		return fFalse;

	if (sev == sevDirFill)
		{
		SetErrorMat(matNil); /* don't need to report another error */
		ErrorEid(eidLowMemLBox, "FRetrySdmError");
		return fFalse;
		}

	if (vsasCur != sasMin)
		{
		ShrinkSwapArea();
		Assert(vsasCur == sasMin);
		return fTrue;
		}

	/* this is necessary since retry may be for windows failure instead of
		a memory failure (memory failures are covered in FRetryLmemError)*/
	SetErrorMat(matLow);

	/* set flags to take down ruler or ribbon if hdlg associated */

	if (hdlg != hdlgNull && hdlg != hdlgCabError && !FModalDlg(hdlg))
		SetEndIbdlg(hdlg);

	/* for major problems, sdm will take down the dialog.
       We no longer call EndDlg ourselves */
	return fFalse;
}


extern int wwCur;
extern KMP ** hkmpCur;
extern KMP ** hkmpBase;
extern MSG vmsgLast;
extern struct WWD ** hwwdCur;
extern vgrfMenuKeysAreDirty;

extern KME vkme;


#define ckmeGrow        10

KME * PkmeFromKc();


extern KMP ** hkmpSearch;
extern int ikmeSearch;


/* R E M O V E  K E Y  F R O M  K M P */
/* %%Function:RemoveKeyFromKmp %%Owner:chic */
RemoveKeyFromKmp(hkmp, kc, bcm)
KMP ** hkmp;
int kc, bcm;
{
	KMP * pkmp;
	KME * pkme;
	int ikme;

	if (FSearchKmp(hkmp, kc, &ikme))
		{
		pkmp = *hkmp;
		pkme = &pkmp->rgkme[ikme];
		bltb(pkme + 1, pkme,
				sizeof (KME) * (--pkmp->ikmeMac - ikme));
		}
}


/* E N D  K E Y  M O D E */
/* Finish mode by calling optional function specified in keymap and
make sure the keymap gets removed from the chain. */
/* %%Function:EndKeyMode %%Owner:chic */
EndKeyMode()
{
	int ikme;
	PFN pfn = NULL;

	/* The following can happen during initialization... */
	if (hkmpCur == hNil || !(*hkmpCur)->fModal)
		return;

	if (FSearchKmp(hkmpCur, kcModal, &ikme))
		{
		pfn = (*hkmpCur)->rgkme[ikme].pfn;
		}

	RemoveKmp(hkmpCur);

	if (pfn)
		(*pfn)();
}


/* F  C O P Y  K M P  T O  K M P */
/* %%Function:FCopyKmpToKmp %%Owner:chic */
FCopyKmpToKmp(hkmpSrc, hkmpDest)
KMP ** hkmpSrc, ** hkmpDest;
{
	int cw;
	/* expr split up due to compiler problems */
	cw = CwOfPfgr(hkmpSrc);
	if (!FChngSizeHCw(hkmpDest, cw, fTrue))
		return fFalse;

	bltb(*hkmpSrc, *hkmpDest, cw * 2);

	return fTrue;
}


#ifdef DEBUG
CMD CmdDumpKeymap(pcmb)
CMB *pcmb;
{
	KMP ** hkmp;
	KMP * pkmp;
	KME * pkme;
	int ikme, ikmeMac;
	char * pch;
	char sz[20];
	for (hkmp = hkmpCur; hkmp != hNil; hkmp = (*hkmp)->hkmpNext)
		{
		extern KMP ** vhkmpUser;
		if (hkmp == hkmpCur)
			CommSz(SzShared("Current!\r\n"));
		if (hkmp == hkmpBase)
			CommSz(SzShared("Base!\r\n"));
		if (hkmp == vhkmpUser)
			CommSz(SzShared("User!\r\n"));
		pkmp = *hkmp;
		CommSzNum(SzShared("ikmeMac:"), ikmeMac = pkmp->ikmeMac);
		CommSzNum(SzShared("grpf: "), pkmp->grpf);
		pch = sz;
		if (pkmp->fStopHere)
			*pch++ = 'S';
		if (pkmp->fModal)
			*pch++ = 'M';
		if (pkmp->fBeep)
			*pch++ = 'B';
		if (pkmp->fTranslate)
			*pch++ = 'T';
		if (pkmp->fAppModal)
			*pch++ = 'A';
		*pch++ = '\0';
		if (*sz != '\0')
			CommSzSz(SzShared("Bits: "), sz);
		CommSz(SzShared("--------------------\r\n"));
		}
#ifdef TOOVERBOSE
	for (pkme = &pkmp->rgkme[ikme = 0]; ikme < ikmeMac; ++ikme, ++pkme)
		{
		CommSzNum(SzShared("kc: "), pkme->kc);
		CommSzNum(SzShared("kt: "), pkme->kt);
		CommSzNum(SzShared("value: "), pkme->w);
		}
#endif
	return cmdOK;
}


#endif /* DEBUG */




#ifdef DEBUG
/* %%Function:CheckHkmp %%Owner:chic */
CheckHkmp(hkmp)
KMP ** hkmp;
{
	KMP * pkmp;
	KME * pkme;
	int kc;
	int ikme, ikmeMac;

	AssertH(hkmp);
	pkmp = *hkmp;

	if (pkmp->hkmpNext != hNil)
		AssertH(pkmp->hkmpNext);

	ikmeMac = pkmp->ikmeMac;
	Assert(ikmeMac >= 0);
	Assert(ikmeMac <= pkmp->ikmeMax);

	/* assert keymap is sorted */
	kc = kcNil;
	for (pkme = &pkmp->rgkme[ikme = 0]; ikme < ikmeMac; ++ikme, ++pkme)
		{
#ifndef INTL
		Assert(pkme->kc > kc);
#else  /* INTL */
		Assert(pkme->kc >= kc);
#endif /* INTL */
		kc = pkme->kc;
		}
}


#endif



#ifdef OPUS_X64
#define ihwndMax 7
#else
#define ihwndMax 6
#endif

/* A P P  S I Z E */
/* handles WM_SIZE message for App window */

/* %%Function:AppSize %%Owner:chic */
AppSize(fShrink)
BOOL fShrink;
{
	struct RC rc;
	int ihwnd = 0;
	int i;
	HWND hwnd, rghwnd[ihwndMax]; /* WARNING: increase if add to rghwnd */

	Assert (!vfInitializing || vhwndDeskTop != NULL);


	if (vhwndStatLine)
		rghwnd[ihwnd++] = vhwndStatLine;

	if (vhwndPrompt)
		rghwnd[ihwnd++] = vhwndPrompt;

	Assert( vhwndDeskTop );
	rghwnd[ihwnd++] = vhwndDeskTop;

	if (vhwndRibbon)
		rghwnd[ihwnd++] = vhwndRibbon;

	if (vhwndAppIconBar != NULL)
		rghwnd[ihwnd++] = vhwndAppIconBar;

#ifdef OPUS_X64
	if (OpusWin95ChromeActive())
		rghwnd[ihwnd++] = vhwndWin95Toolbar;
#endif

	if (vhwndPgPrvw != NULL)
		rghwnd[ihwnd++] = vhwndPgPrvw;

	i = ihwnd;
	Assert(i <= ihwndMax);
	ihwnd = (fShrink ? i - 1 : 0);

	/* This loop is set up to loop forwards through the hwnds if
		we are growing the Application and backwards if we are
		shrinking it. */

	while (i--)
		{
		hwnd = rghwnd[ihwnd];

		if (hwnd == vhwndStatLine || hwnd == vhwndPrompt)
			{
			Assert( vsci.dypStatLine );
			GetClientRect( vhwndApp, (LPRECT) &rc );
			rc.ypBottom += vsci.dypBorder;
			rc.ypTop = rc.ypBottom - vsci.dypStatLine;
			rc.xpLeft -= vsci.dxpBorder;
			rc.xpRight += vsci.dxpBorder;
			MoveWindowRc( hwnd, &rc, fTrue );
			}
		else  if (hwnd == vhwndDeskTop)
			{
			GetDeskTopPrc( &rc );
			MoveWindowRc( vhwndDeskTop, &rc, fTrue );
			}
		else  if (hwnd == vhwndRibbon || hwnd == vhwndAppIconBar)
			{
#ifdef OPUS_X64
			if (hwnd == vhwndRibbon && OpusWin95ChromeActive())
				ShowWindow(hwnd, SW_HIDE);
			else
#endif
				{
/* NOTE: height of ribbon and macro iconbar are the same - dypRibbon
but outline and header iconbar should be dypIconBar */
				Assert( vsci.dypRibbon );
				GetClientRect( vhwndApp, (LPRECT) &rc );
				rc.ypTop -= vsci.dxpBorder;
				rc.xpLeft -= vsci.dxpBorder;
				rc.xpRight += vsci.dxpBorder;
				rc.ypBottom = rc.ypTop + vsci.dypRibbon;
				MoveWindowRc( hwnd, &rc, fTrue );
				}
			}
#ifdef OPUS_X64
		else if (hwnd == vhwndWin95Toolbar)
			OpusSizeWin95Toolbar(vhwndApp);
#endif
		else  if (hwnd == vhwndPgPrvw)
			{
			GetClientRect(vhwndApp, (LPRECT) &rc);
			/* leave room for preview icon bar */
			rc.ypTop += (vsci.dypRibbon - vsci.dypBorder);
			MoveWindowRc( hwnd, &rc, fTrue );
			}

		ihwnd += (fShrink ? -1 : 1);
		}
}



/* G E T  D E S K  T O P  P R C */

/* Return rect for desktop through parm.
	Results depend on:
			(1) size of app window
			(2) presence of ribbon
			(3) presence of status line */

/* %%Function:GetDeskTopPrc %%Owner:chic */
GetDeskTopPrc( prc )
struct RC *prc;
{
	GetClientRect( vhwndApp, (LPRECT)prc );

	if (vhwndStatLine)
		{
		Assert( vsci.dypStatLine );
		prc->ypBottom -= vsci.dypStatLine - vsci.dypBorder;
		}
	if (vhwndRibbon || vhwndAppIconBar != NULL)
		{
#ifdef OPUS_X64
		if (OpusWin95ChromeActive())
			goto LWin95Toolbar;
#endif
/* NOTE: height of ribbon and macro iconbar are the same - dypRibbon
but outline and header iconbar should be dypIconBar */
		Assert( vsci.dypRibbon );
		prc->ypTop += vsci.dypRibbon - vsci.dypBorder;
		}
#ifdef OPUS_X64
LWin95Toolbar:
	if (OpusWin95ChromeActive())
		{
		int dypWin95Toolbar = OpusWin95ToolbarHeight();
		if (dypWin95Toolbar > 0)
			prc->ypTop += dypWin95Toolbar - vsci.dypBorder;
		}
#endif
}


/* G E T  N O N  P A N E  R G D Y P */
/* get height of non pane area in ww (currently that includes
	ruler/iconbar only) */

/* %%Function:GetNonPaneRgdyp %%Owner:chic */
GetNonPaneRgdyp(hmwd, rgdyp)
struct MWD **hmwd;
int rgdyp[];
{
	int iww, ww;

	rgdyp[0] = rgdyp[1] = 0;

	for ( iww = 0 ; iww < 2 ; iww++ )
		if ((ww = (*hmwd)->rgww[iww]) != wwNil)
			{
			if (ww == (*hmwd)->wwRuler)
				rgdyp[iww] += vsci.dypRuler - vsci.dypBorder;
			if (PwwdWw(ww)->hwndIconBar)
				rgdyp[iww] += vsci.dypIconBar - vsci.dypBorder;
			}
}



/* %%Function:AdjustStyNameDxw %%Owner:chic */
AdjustStyNameDxw(hmwd, pdxw)
struct MWD **hmwd;
int *pdxw;
{
	int dxwNew = *pdxw;
	struct RC rc;

	if (dxwNew <= vsci.dxpBorder)
	/* not worth it */
		dxwNew = 0;
	else
		{
		GetClientRect((*hmwd)->hwnd, (LPRECT)&rc);
		dxwNew = min(rc.xpRight>>1, dxwNew); /* make sure dxpNew is not too big */
		}
	*pdxw = dxwNew;
}




/*  Resize MWDs as necessary so they won't be obscured if Status Line
	or Ribbon is brought up. */

/* %%Function:ResizeMwds %%Owner:chic */
ResizeMwds()
{
	int ihwnd;
	struct RC rc, rcT;
	HWND hwnd;
	HWND rghwnd[mwMax];
	int ypBottom;

	if (hmwdCur == hNil) /* fairly bogus test to see if any windows are open */
		return; /* nothing to do! */

	/* get top to bottom list of windows */

	rghwnd[ihwnd = 0] = (*hmwdCur)->hwnd;

	while ((hwnd = rghwnd[ihwnd]) != hNil)
		{
		rghwnd[++ihwnd] = GetNextWindow(hwnd, GW_HWNDNEXT);
		Assert (ihwnd < mwMax);
		}
	GetClientRect(vhwndDeskTop, (LPRECT) &rcT);

	/* move the windows in reverse order so that all windows are
	stacked in the right order and the current one is on top */

	while (ihwnd > 0)
		{
		GetWindowRect( rghwnd[--ihwnd], (LPRECT) &rc );
		ScreenToClient( vhwndDeskTop, (LPPOINT) &rc.ptTopLeft );
		ScreenToClient( vhwndDeskTop, (LPPOINT) &rc.ptBottomRight );
		ypBottom = rc.ypBottom;
		if (ypBottom > rcT.ypBottom + vsci.dypBorder)
			{
			rc.ypBottom = rcT.ypBottom;
			MoveWindowRc( rghwnd[ihwnd], &rc, fTrue );
			}
		}
}




/* A D D  L O O K S  K E Y S */
/* Add all of the character and paragraph formatting keyboard commands
	from hkmpSearch to hkmpAdd. */
/* %%Function:AddLooksKeys %%Owner:chic */
AddLooksKeys(hkmpSearch, hkmpAdd, ilcdMaxAdd)
KMP ** hkmpSearch, ** hkmpAdd;
int ilcdMaxAdd;
{
	KMP ** hkmpCurSav;
	int ilcd, bcm;

	Assert(ilcdMaxAdd <= sizeof(mpilcdbcm)/sizeof(int));

	hkmpCurSav = hkmpCur;
	hkmpCur = hkmpSearch;

	/*  warning - strong position dependance on bcm, ilcd  */
	for (ilcd = 0; ilcd < ilcdMaxAdd; ++ilcd)
		if ((bcm = mpilcdbcm [ilcd]) != bcmNil)
			AddAllKeysOfBcm(hkmpSearch, hkmpAdd, bcm, bcm);

	hkmpCur = hkmpCurSav;
}


/* R E C O R D  L O O K S */
/* %%Function:RecordLooks %%Owner:chic */
RecordLooks(ilcd)
int ilcd;
{
	int bcm = mpilcdbcm [ilcd];

	Assert(vfRecording);
	if (bcm != bcmNil)
		GenStatement(bcm);
}


/* A D D  K E Y  K T  W */
/* Bind a key of an arbitrary type */
/* %%Function:AddKeyKtW %%Owner:chic */
AddKeyKtW(hkmp, kc, kt, w)
KMP ** hkmp;
int kc, kt, w;
{
	KME * pkme;

	pkme = PkmeAddKc(hkmp, kc);
	if (pkme != 0)
		{
		pkme->kt = kt;
		pkme->w = w;
		}
}



/* F E D T  R A R E  R O U T I N E S */

#include "fedt.h"

/* Macros to keep the rest of this module as Excel-like as reasonable */

#define fAlt        (wKbsOptionMask)
#define fShift      (wKbsShiftMask)
#define fControl    (wKbsControlMask)
#define FOREVER     for ( ;; )
#define chLF        (chEol)
#define chBackSpace (chBS)
#define chNull      '\0'
#define SzLen(sz)   (CchSz(sz)-1)

#define pfedt (*hfedt)

/*----------------------------------------------------------------------------
|    FFedtCopy
|
|    Performs the Copy command on the given fedt control, i.e., puts
|    the text of the current selection in the clipboard.
|
|    Arguments:
|        phfedt        pointer to fedt control to copy from
|
|    Returns:
|        TRUE if successful
----------------------------------------------------------------------------*/
/* %%Function:FFedtCopy %%Owner:bobz */
BOOL FFedtCopy(phfedt)
FEDT ***phfedt;
{
	char *pch;
	int ich, cch;
	HANDLE hdata;
	FEDT **hfedt;
	char far *lpch;

	hfedt = *phfedt;
	Debug(CheckFedt(hfedt));

	if (!OpenClipboard(pfedt->hwnd))
		return(FALSE);
	EmptyClipboard();
	pch = PchFromHsz(pfedt->hszText) + pfedt->ichMicSel;
	cch = pfedt->ichMacSel - pfedt->ichMicSel;
	cch += CchCountCh(pch, pch + cch, chLF);
	while ((hdata = OurGlobalAlloc(GHND, (long)(uns)(cch+1))) == NULL)
		{
		switch (LOWORD(FedtNotifyParent(&hfedt, FN_ERRSPACE|FN_OOMCOPY)))
			{
		case FN_OOMALERT:
LError:
			SetErrorMat(matMem);
		case FN_OOMABORT:
		case FN_OOMIGNORE:
			CloseClipboard();
			*phfedt = hfedt;
			return(FALSE);
		case FN_OOMRETRY:
			break;
			}
		}
	if ((lpch = GlobalLockClip(hdata)) == NULL)
		goto LError;
	for (ich = pfedt->ichMicSel; ich < pfedt->ichMacSel; ich++)
		{
		/* map linefeeds into cr-lf */
		if (*pch == chLF)
			*lpch++ = chReturn;
		*lpch++ = *pch++;
		}
	*lpch = 0;
	GlobalUnlock(hdata);
	SetClipboardData(CF_TEXT, hdata);
	CloseClipboard();
	*phfedt = hfedt;
	return(TRUE);
}


/*----------------------------------------------------------------------------
|    FFedtClear
|
|    Clears the text of the current selection in the given fedt control.
|
|    Arguments:
|        phfedt        fedt control to clear the selection in
|
|    Returns:
|        TRUE if successful
----------------------------------------------------------------------------*/
/* %%Function:FFedtClear %%Owner:bobz */
BOOL FFedtClear(phfedt)
FEDT ***phfedt;
{
	char rgch[2];

	Debug(CheckFedt(*phfedt));

	if (!FFedtReplSel(phfedt, (char far *)rgch, 0))
		return(FALSE);
	FedtAdjustSel(*phfedt);
	return(TRUE);
}


/*----------------------------------------------------------------------------
|    FFedtPaste
|
|    Performs the Paste operation to the given fedt control, i.e.,
|    replaces the current selection with the text from the clipboard.
|
|    Arguments:
|        phfedt
|
|    Returns:
|        TRUE if successful
----------------------------------------------------------------------------*/
/* %%Function:FFedtPaste %%Owner:bobz */
BOOL FFedtPaste(phfedt)
FEDT ***phfedt;
{
	char far *lpch;
	HANDLE hdata, hdata2;
	FEDT **hfedt;
	HANDLE HFedtStripText();

	hfedt = *phfedt;
	Debug(CheckFedt(hfedt));

	if (!OpenClipboard(pfedt->hwnd))
		return(FALSE);
	hdata = GetClipboardData(CF_TEXT);
	/* BUG!! - it would be nice if we allowed LFs in chart alpha
		pasting */
	if ((hdata2 = HFedtStripText(hfedt, hdata)) == NULL
			|| (lpch = GlobalLockClip(hdata2)) == NULL)
		{
		CloseClipboard();
		return(FALSE);
		}
	if (FFedtReplSel(&hfedt, lpch, CchLpszLen(lpch)))
		FedtAdjustSel(hfedt);
	GlobalUnlock(hdata2);
	if (hdata != hdata2)
		GlobalFree(hdata2);
	CloseClipboard();
	*phfedt = hfedt;
	return(TRUE);
}


/*----------------------------------------------------------------------------
|    HFedtStripText
|
|    Strips text of all bizzaro characters.
|
|    Arguments:
|        hdata        handle to global object containing
|                text to check.
|
|    Returns:
|        handle to modified new object, hdata if data is ok, or
|        NULL if errors.
----------------------------------------------------------------------------*/
/* %%Function:HFedtStripText %%Owner:bobz */
HANDLE HFedtStripText(hfedt, hdata)
FEDT **hfedt;
HANDLE hdata;
{
	char far *lpch, far *lpchSav, far *lpch2;
	int ch;
	int fStopAtLF = pfedt->fSingleLine;
	HANDLE hdata2;

	if (hdata == NULL || (lpch = GlobalLock(hdata)) == NULL)
		return(NULL);

	lpchSav = lpch;
	/* look for ugly characters in the text */
	while  ((ch = *lpch++) != chNull)
		{
		if (ch < chSpace)
			{
			/* found an ugly character - allocate a work area and
				copy modified text into it */
/* NOTE: GHND 0-inits, no terminator necessary */
			hdata2 = OurGlobalAlloc(GHND, GlobalSize(hdata));
			if (hdata2 == NULL || (lpch2 = GlobalLock(hdata2)) == NULL)
				SetErrorMat(matMem);
			else
				{
				lpch = lpchSav;
				while ((ch = *lpch) != chNull)
					{
					if (ch < chSpace)
						{
						if (ch == chReturn)
							{
							ch = chLF;
							if (*(lpch+1) == chLF)
								lpch++;
							}
						if (ch == chLF)
							{
							if (fStopAtLF)
								break;
							}
						else
							ch = chSpace;
						}
					*lpch2++ = ch;
					lpch++;
					}
				GlobalUnlock(hdata);
				}
			hdata = hdata2;
			break;
			}
		}
	if (hdata != NULL)
		GlobalUnlock(hdata);
	return(hdata);
}
