
/*
 * WINDOWS.C
 * (c) 1992-3 J.Harper
 */

#include "jed.h"
#include "revision.h"
#include "jed_protos.h"

Prototype   VALUE * cmd_newfile		(LONG, VALUE *);
Prototype   BOOL    newfile		(STRPTR);
Prototype   VALUE * cmd_newview		(LONG, VALUE *);
Prototype   BOOL    newview		(VOID);
Prototype   VALUE * cmd_close		(LONG, VALUE *);
Prototype   VOID    killwindow		(VOID);
Prototype   VALUE * cmd_sleep		(LONG, VALUE *);
Prototype   VALUE * cmd_unsleep		(LONG, VALUE *);
Prototype   BOOL    unsleep		(VOID);
Prototype   VALUE * cmd_dlock		(LONG, VALUE *);
Local	    TX *    newtx		(VOID);
Local	    VOID    killtx		(TX *);
Local	    VW *    newvw		(TX *, struct Window *, VW *);
Local	    VOID    killvw		(VW *);
Prototype   WORD    numtxs		(VOID);
Prototype   WORD    numviews		(TX *);
Prototype   VOID    updatedimensions	(VW *);
Local struct Window *newwindow		(UWORD *, STRPTR);
Local	    VOID    CloseSharedWindow	(struct Window *);
Local	    VOID    StripIntuiMessages	(struct MsgPort *, struct Window *);
Prototype   struct IntuiMessage *GetWinIMsg(struct Window *);
Prototype   VALUE * cmd_nextwind	(LONG, VALUE *);
Prototype   VALUE * cmd_prevwind	(LONG, VALUE *);
Prototype   VALUE * cmd_activatefile	(LONG, VALUE *);
Prototype   BOOL    activatefile	(STRPTR);
Prototype   VOID    settitle		(STRPTR);
Prototype   VOID    settitlefmt		(STRPTR, ULONG, ...);
Prototype   VALUE * cmd_settitle	(LONG, VALUE *);
Prototype   VOID    notitle		(VOID);
Prototype   VOID    stdtitle		(VOID);
Prototype   VOID    resettitle		(VOID);
Prototype   LONG    ezreq		(STRPTR, STRPTR, LONG, ...);
Prototype   VALUE * cmd_req		(LONG, VALUE *);
Prototype   BOOL    setfont		(VW *);
Prototype   VALUE * cmd_rename		(LONG, VALUE *);
Prototype   VALUE * cmd_changes		(LONG, VALUE *);
Prototype   VALUE * cmd_position	(LONG, VALUE *);
Prototype   VOID    resetslptxtitles	(TX *);

Prototype   struct MinList TXList;
Prototype   VW		  *CurrVW;
Prototype   WORD	   NumWindows;

struct MinList TXList;
VW	      *CurrVW;
WORD	       NumWindows;

#define IDCMP (IDCMP_NEWSIZE | IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE \
	| IDCMP_MENUPICK | IDCMP_CLOSEWINDOW | IDCMP_RAWKEY \
	| IDCMP_ACTIVEWINDOW)

#define SIDCMP (IDCMP_MOUSEBUTTONS | IDCMP_CLOSEWINDOW \
	| IDCMP_RAWKEY)

#define WFLAGS (WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET \
	| WFLG_SIZEGADGET | WFLG_REPORTMOUSE | WFLG_ACTIVATE \
	| WFLG_SMART_REFRESH | WFLG_NOCAREREFRESH)

#define SWFLAGS (WFLG_DRAGBAR | WFLG_CLOSEGADGET | WFLG_ACTIVATE \
	| WFLG_SMART_REFRESH | WFLG_NOCAREREFRESH | WFLG_RMBTRAP)

Local const UBYTE ScreenTitle[] = VERSSTRING " (" __DATE__ ") Copyright © J.Harper";
Local struct MsgPort *SharedPort;

/*
 * (newfile `fileName')
 */
VALUE *
cmd_newfile(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
    {
	BOOL rc = newfile(ARG1.val_Value.String);
	setnumres(rc);
	if(!rc)
	    settitle(NoMemMsg);
    }
    return(&RES);
}

BOOL
newfile(STRPTR fileName)
{
    TX *tx;
    VW *oldvw = CurrVW;
    struct Window *wd;

    if(oldvw)
    {
	if(oldvw->vw_Sleeping)
	    wd = newwindow(oldvw->vw_OldDimensions, oldvw->vw_Prefs.prf_ScreenName);
	else
	    wd = newwindow(&oldvw->vw_Window->LeftEdge, oldvw->vw_Prefs.prf_ScreenName);
    }
    else
	wd = newwindow(DefDims, DefPrefs.prf_ScreenName);
    if(wd)
    {
	NumWindows++;
	setmenu(wd);
	if(tx = newtx())
	{
	    if(oldvw)
		cursor(ON);
	    if(CurrVW = newvw(tx, wd, oldvw))
	    {
		if(readtx(tx, fileName, CurrVW->vw_Prefs.prf_DiskTab))
		{
		    setupfileprefs(tx);
		    CurrVW->vw_RefreshType = RFF_ALL;
		    stdtitle();
		    return(TRUE);
		}
		killvw(CurrVW);
	    }
	    CurrVW = oldvw;
	    if(oldvw)
		cursor(OFF);
	    killtx(tx);
	}
	CloseSharedWindow(wd);
    }
    return(FALSE);
}

/*
 * (newview)
 */
VALUE *
cmd_newview(LONG argc, VALUE *argv)
{
    BOOL rc = newview();
    setnumres(rc);
    if(!rc)
	settitle(NoMemMsg);
    return(&RES);
}

BOOL
newview(VOID)
{
    struct Window *wd;
    TX *tx;
    VW *oldvw = CurrVW;

    if(oldvw->vw_Sleeping)
	wd = newwindow(oldvw->vw_OldDimensions, oldvw->vw_Prefs.prf_ScreenName);
    else
	wd = newwindow(&oldvw->vw_Window->LeftEdge, oldvw->vw_Prefs.prf_ScreenName);
    if(wd)
    {
	NumWindows++;
	setmenu(wd);
	cursor(ON);
	if(CurrVW = newvw(oldvw->vw_Tx, wd, oldvw));
	{
	    CurrVW->vw_RefreshType = RFF_ALL;
	    cursor(ON);
	    stdtitle();
	    return(TRUE);
	}
	CurrVW = oldvw;
	cursor(OFF);
	CloseSharedWindow(wd);
    }
    return(FALSE);
}

/*
 * (close)
 */
VALUE *
cmd_close(LONG argc, VALUE *argv)
{
    TX *tx = CurrVW->vw_Tx;
    if((numviews(tx) > 1) || (!tx->tx_Changes) || (ezreq("OK to lose %ld changes\nto file %s", "Yeah|Cancel", tx->tx_Changes, tx->tx_TitleName)))
    {
	killwindow();
	setnumres(TRUE);
    }
    else
	setnumres(FALSE);
    return(&RES);
}

VOID
killwindow(VOID)
{
    VW *vw = CurrVW;
    TX *tx = vw->vw_Tx;

    setdefprefs(vw);
    notitle();
    CloseSharedWindow(vw->vw_Window);
    killvw(vw);
    if(IsMListEmpty(tx->tx_Views))
    {
	killtx(tx);
	if(IsMListEmpty(TXList))
	    CurrVW = NULL;
	else
	    CurrVW = (VW *)((TX *)TXList.mlh_Head)->tx_Views.mlh_Head;
    }
    else
	CurrVW = (VW *)tx->tx_Views.mlh_Head;
    if(CurrVW)
    {
	CurrVW->vw_DeferRefresh++;
	cursor(OFF);
    }
}

/*
 * Sleeps the window.
 */
VALUE *
cmd_sleep(LONG argc, VALUE *argv)
{
    VW *vw = CurrVW;
    if(!vw->vw_Sleeping)
    {
	struct Window *swin;
	if(swin = OpenWindowTags(NULL,
	    WA_Left, 0,
	    WA_Top, 0,
	    WA_Width, 150,
	    WA_Height, vw->vw_Window->BorderTop,
	    WA_IDCMP, 0,
	    WA_Flags, SWFLAGS,
	    WA_Title, vw->vw_Tx->tx_TitleName,
	    WA_ScreenTitle, ScreenTitle,
	    WA_AutoAdjust, TRUE,
	    WA_PubScreenName, vw->vw_Prefs.prf_ScreenName,
	    WA_PubScreenFallBack, TRUE,
	    TAG_END))
	{
	    swin->UserPort = SharedPort;
	    ModifyIDCMP(swin, SIDCMP);

	    vw->vw_OldDimensions[0] = vw->vw_Window->LeftEdge;
	    vw->vw_OldDimensions[1] = vw->vw_Window->TopEdge;
	    vw->vw_OldDimensions[2] = vw->vw_Window->Width;
	    vw->vw_OldDimensions[3] = vw->vw_Window->Height;

	    clearmenu(vw->vw_Window);
	    Forbid();
	    StripIntuiMessages(vw->vw_Window->UserPort, vw->vw_Window);
	    vw->vw_Window->UserPort = NULL;
	    ModifyIDCMP(vw->vw_Window, 0L);
	    Permit();
	    CloseWindow(vw->vw_Window);

	    vw->vw_Window = swin;
	    vw->vw_Rp = swin->RPort;
	    vw->vw_Sleeping = TRUE;
	    swin->UserData = (BYTE *)vw;
	    setnumres(TRUE);
	}
	else
	{
	    settitle("error: can't open window to sleep in");
	    setnumres(FALSE);
	}
    }
    return(&RES);
}

VALUE *
cmd_unsleep(LONG argc, VALUE *argv)
{
    if(CurrVW->vw_Sleeping)
    {
	setnumres(unsleep());
    }
    return(&RES);
}

BOOL
unsleep(VOID)
{
    VW *vw = CurrVW;
    BOOL rc = TRUE;
    if(vw->vw_Sleeping)
    {
	struct Window *nwin;

	if(nwin = newwindow(vw->vw_OldDimensions, vw->vw_Prefs.prf_ScreenName))
	{
	    setmenu(nwin);

	    Forbid();
	    StripIntuiMessages(vw->vw_Window->UserPort, vw->vw_Window);
	    vw->vw_Window->UserPort = NULL;
	    ModifyIDCMP(vw->vw_Window, 0L);
	    Permit();
	    CloseWindow(vw->vw_Window);

	    vw->vw_Window = nwin;
	    vw->vw_Rp = nwin->RPort;
	    vw->vw_Sleeping = FALSE;
	    nwin->UserData = (BYTE *)vw;
	    SetFont(vw->vw_Rp, vw->vw_Font);
	    updatedimensions(vw);
	    vw->vw_RefreshType = RFF_ALL;
	}
	else
	    rc = FALSE;
    }
    return(rc);
}

VALUE *
cmd_dlock(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_NUMBER))
    {
	VW *vw = CurrVW;
	vw->vw_DisplayLock = ARG1.val_Value.Number;
	setnumres(TRUE);
    }
    return(&RES);
}

/*
 * Creates a new TX structure
 */
Local TX *
newtx(VOID)
{
    TX *tx = AllocVec(sizeof(TX), MEMF_CLEAR);
    if(tx)
    {
	AddMTail(&TXList, &tx->tx_Node);
	NewMList(&tx->tx_Views);
	NewMList(&tx->tx_Marks);
	return(tx);
    }
    return(FALSE);
}

Local VOID
killtx(TX *tx)
{
    RemoveM(&tx->tx_Node);
    killlinelist(tx);
    freestring(tx->tx_TitleName);
    freestring(tx->tx_FileName);
    FreeVec(tx);
}

/*
 * Creates a new VW, oldVW is used to copy prefs from, can be NULL.
 */
Local VW *
newvw(TX *tx, struct Window *wd, VW *oldVW)
{
    VW *vw = AllocVec(sizeof(VW), MEMF_CLEAR);
    if(vw)
    {
	vw->vw_Window = wd;
	vw->vw_Rp = wd->RPort;
	vw->vw_Tx = tx;
	wd->UserData = (BYTE *)vw;
	copyprefs(vw, oldVW);
	if(setfont(vw))
	{
	    updatedimensions(vw);
	    vw->vw_BlockStatus = -1;
	    AddMTail(&tx->tx_Views, &vw->vw_Node);
	    return(vw);
	}
	FreeVec(vw);
    }
    return(FALSE);
}

Local VOID
killvw(VW *vw)
{
    RemoveM(&vw->vw_Node);
    freestring(vw->vw_LineUndo.text);
    CloseFont(vw->vw_Font);
#ifndef NOREGEXP
    if(vw->vw_LastRE.prog)
	free(vw->vw_LastRE.prog);
#endif
    FreeVec(vw);
}

WORD
numtxs(VOID)
{
    WORD i =0;
    TX *tx = (TX *)TXList.mlh_Head;
    while(tx = (TX *)tx->tx_Node.mln_Succ)
	i++;
    return(i);
}

WORD
numviews(TX *tx)
{
    WORD i = 0;
    VW *vw = (VW *)tx->tx_Views.mlh_Head;
    while(vw = (VW *)vw->vw_Node.mln_Succ)
	i++;
    return(i);
}

VOID
updatedimensions(VW *vw)
{
    if(!vw->vw_Sleeping)
    {
	struct Window *wd = vw->vw_Window;

	vw->vw_XStartPix = (UWORD)wd->BorderLeft;
	vw->vw_YStartPix = (UWORD)wd->BorderTop;
	vw->vw_XEndPix = wd->Width - (UWORD)wd->BorderRight - 1;
	vw->vw_YEndPix = wd->Height - (UWORD)wd->BorderBottom;
	vw->vw_XWidthPix = vw->vw_XEndPix - vw->vw_XStartPix;
	vw->vw_YHeightPix = vw->vw_YEndPix - vw->vw_YStartPix;

	vw->vw_FontStart = vw->vw_YStartPix + vw->vw_Font->tf_Baseline;
	vw->vw_FontX = vw->vw_Font->tf_XSize;
	vw->vw_FontY = vw->vw_Font->tf_YSize;

	vw->vw_MaxX = (vw->vw_XWidthPix / vw->vw_FontX);
	vw->vw_MaxY = (vw->vw_YHeightPix / vw->vw_FontY);
	vw->vw_XStep = vw->vw_MaxX / 4;
	if(!vw->vw_XStep)
	    vw->vw_XStep = 1;
    }
}

/*
 * Opens an editor window. Sets up the shared IDCMP
 */
Local struct Window *
newwindow(UWORD *dimensions, STRPTR pubName)
{
    struct Window *res;
    res = OpenWindowTags(NULL,
	WA_Left, dimensions[0],
	WA_Top, dimensions[1],
	WA_Width, dimensions[2],
	WA_Height, dimensions[3],
	WA_IDCMP, SharedPort ? 0 : IDCMP,
	WA_MinWidth, 80,
	WA_MinHeight, 40,
	WA_MaxWidth, ~0,
	WA_MaxHeight, ~0,
	WA_Flags, WFLAGS,
	WA_ScreenTitle, ScreenTitle,
	WA_AutoAdjust, TRUE,
	WA_PubScreenName, pubName,
	WA_PubScreenFallBack, TRUE,
	WA_RptQueue, 2,
	TAG_END);
    if(res)
    {
	if(SharedPort)
	{
	    res->UserPort = SharedPort;
	    ModifyIDCMP(res, IDCMP);
	}
	else
	    SharedPort = res->UserPort;
    }
    return(res);
}

/*
 * Code to close a window who's sharing a UserPort -- taken from
 * CloseWindow() autodoc.
 */
Local VOID
CloseSharedWindow(struct Window *win)
{
    clearmenu(win);
    if(--NumWindows)
    {
	Forbid();
	StripIntuiMessages(win->UserPort, win);
	win->UserPort = NULL;
	ModifyIDCMP(win, 0L);
	Permit();
    }
    else
	SharedPort = NULL;
    CloseWindow(win);
}

Local VOID
StripIntuiMessages(struct MsgPort *mp, struct Window *win)
{
    struct IntuiMessage *msg;
    struct Node *succ;

    msg = (struct IntuiMessage *)mp->mp_MsgList.lh_Head;
    while(succ = msg->ExecMessage.mn_Node.ln_Succ)
    {
	if(msg->IDCMPWindow == win)
	{
	    Remove((struct Node *)msg);
	    ReplyMsg((struct Message *)msg);
	}
	msg = (struct IntuiMessage *)succ;
    }
}

/*
 * Gets the next Imsg for the specified window -- this is used for event
 * loops local to a single window
 */
struct IntuiMessage *
GetWinIMsg(struct Window *win)
{
    struct IntuiMessage *msg;
    struct Node *succ;

    Forbid();
    msg = (struct IntuiMessage *)win->UserPort->mp_MsgList.lh_Head;
    while(succ = msg->ExecMessage.mn_Node.ln_Succ)
    {
	if(msg->IDCMPWindow == win)
	{
	    Remove((struct Node *)msg);
	    Permit();
	    return(msg);
	}
	msg = (struct IntuiMessage *)succ;
    }
    Permit();
    return(FALSE);
}

VALUE *
cmd_nextwind(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
    {
	cursor(ON);
	switch(toupper(*(ARG1.val_Value.String)))
	{
	    case 'F':
		TX *tx = CurrVW->vw_Tx;
		tx = (TX *)tx->tx_Node.mln_Succ;
		if(!tx->tx_Node.mln_Succ)
		    tx = (TX *)TXList.mlh_Head;
		CurrVW = (VW *)tx->tx_Views.mlh_Head;
		WindowToFront(CurrVW->vw_Window);
		ActivateWindow(CurrVW->vw_Window);
		CurrVW->vw_DeferRefresh = 1;
		setnumres(TRUE);
		break;
	    case 'V':
		VW *vw = (VW *)CurrVW->vw_Node.mln_Succ;
		if(!vw->vw_Node.mln_Succ)
		    vw = (VW *)CurrVW->vw_Tx->tx_Views.mlh_Head;
		CurrVW = vw;
		WindowToFront(CurrVW->vw_Window);
		ActivateWindow(CurrVW->vw_Window);
		CurrVW->vw_DeferRefresh = 1;
		setnumres(TRUE);
		break;
	    case 'A':
		VW *vw = (VW *)CurrVW->vw_Node.mln_Succ;
		if(!vw->vw_Node.mln_Succ)
		{
		    TX *tx = (TX *)CurrVW->vw_Tx->tx_Node.mln_Succ;
		    if(!tx->tx_Node.mln_Succ)
			tx = (TX *)TXList.mlh_Head;
		    CurrVW = (VW *)tx->tx_Views.mlh_Head;
		}
		else
		    CurrVW = vw;
		WindowToFront(CurrVW->vw_Window);
		ActivateWindow(CurrVW->vw_Window);
		CurrVW->vw_DeferRefresh = 1;
		setnumres(TRUE);
		break;
	    default:
		settitle(BadArgMsg);
		break;
	}
	cursor(OFF);
    }
    return(&RES);
}

VALUE *
cmd_prevwind(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
    {
	cursor(ON);
	switch(toupper(*ARG1.val_Value.String))
	{
	    case 'F':
		TX *tx = CurrVW->vw_Tx;
		tx = (TX *)tx->tx_Node.mln_Pred;
		if(!tx->tx_Node.mln_Pred)
		    tx = (TX *)TXList.mlh_TailPred;
		CurrVW = (VW *)tx->tx_Views.mlh_TailPred;
		WindowToFront(CurrVW->vw_Window);
		ActivateWindow(CurrVW->vw_Window);
		CurrVW->vw_DeferRefresh = 1;
		setnumres(TRUE);
		break;
	    case 'V':
		VW *vw = (VW *)CurrVW->vw_Node.mln_Pred;
		if(!vw->vw_Node.mln_Pred)
		    vw = (VW *)CurrVW->vw_Tx->tx_Views.mlh_TailPred;
		CurrVW = vw;
		WindowToFront(CurrVW->vw_Window);
		ActivateWindow(CurrVW->vw_Window);
		CurrVW->vw_DeferRefresh = 1;
		setnumres(TRUE);
		break;
	    case 'A':
		VW *vw = (VW *)CurrVW->vw_Node.mln_Pred;
		if(!vw->vw_Node.mln_Pred)
		{
		    TX *tx = (TX *)CurrVW->vw_Tx->tx_Node.mln_Pred;
		    if(!tx->tx_Node.mln_Pred)
			tx = (TX *)TXList.mlh_TailPred;
		    CurrVW = (VW *)tx->tx_Views.mlh_TailPred;
		}
		else
		    CurrVW = vw;
		WindowToFront(CurrVW->vw_Window);
		ActivateWindow(CurrVW->vw_Window);
		CurrVW->vw_DeferRefresh = 1;
		setnumres(TRUE);
		break;
	    default:
		settitle(BadArgMsg);
		break;
	}
	cursor(OFF);
    }
    return(&RES);
}

VALUE *
cmd_activatefile(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
	setnumres(activatefile(ARG1.val_Value.String));
    return(&RES);
}

BOOL
activatefile(STRPTR file)
{
    cursor(ON);
    BPTR lock1 = Lock(file, SHARED_LOCK);
    if(lock1)
    {
	TX *thistx = TXList.mlh_Head;
	while(thistx->tx_Node.mln_Succ)
	{
	    BPTR lock2 = Lock(thistx->tx_FileName, SHARED_LOCK);
	    if(lock2)
	    {
		if(SameLock(lock1, lock2) == LOCK_SAME)
		{
		    CurrVW = (VW *)thistx->tx_Views.mlh_Head;
		    unsleep();
		    WindowToFront(CurrVW->vw_Window);
		    ActivateWindow(CurrVW->vw_Window);
		    UnLock(lock2);
		    UnLock(lock1);
		    cursor(OFF);
		    CurrVW->vw_DeferRefresh = 1;
		    return(TRUE);
		}
		UnLock(lock2);
	    }
	    thistx = (TX *)thistx->tx_Node.mln_Succ;
	}
	UnLock(lock1);
	if(newfile(file))
	{
	    cursor(OFF);
	    return(TRUE);
	}
    }
    else
	settitlefmt("error: unknown file %s", (LONG)file);
    cursor(OFF);
    return(FALSE);
}

VOID
settitle(STRPTR title)
{
    VW *vw = CurrVW;
    if(!vw->vw_Sleeping)
    {
	freestring(vw->vw_LastTitle);
	vw->vw_LastTitle = savestring(title);
	SetWindowTitles(CurrVW->vw_Window, vw->vw_LastTitle, (UBYTE *)-1L);
	vw->vw_NonStdTitle = TRUE;
    }
}

VOID
settitlefmt(STRPTR fmt, ULONG arg1, ...)
{
    VW *vw = CurrVW;
    if(!vw->vw_Sleeping)
    {
	UBYTE fmtbuff[256];
	vsprintf(fmtbuff, fmt, &arg1);
	freestring(vw->vw_LastTitle);
	vw->vw_LastTitle = savestring(fmtbuff);
	SetWindowTitles(vw->vw_Window, vw->vw_LastTitle, (UBYTE *)-1L);
	vw->vw_NonStdTitle = TRUE;
    }
}

VALUE *
cmd_settitle(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
    {
	settitle(ARG1.val_Value.String);
	setnumres(TRUE);
    }
    return(&RES);
}

VOID
notitle(VOID)
{
    VW *vw = CurrVW;
    if(!vw->vw_Sleeping)
    {
	freestring(vw->vw_LastTitle);
	vw->vw_LastTitle = NULL;
	SetWindowTitles(vw->vw_Window, NULL, (UBYTE *)-1L);
	vw->vw_NonStdTitle = FALSE;
    }
}

VOID
stdtitle(VOID)
{
    VW *vw = CurrVW;
    if((!vw->vw_NonStdTitle) && (!vw->vw_Sleeping))
    {
	TX *tx = vw->vw_Tx;
	UBYTE blk;
	UBYTE fmtbuff[100];
	if(vw->vw_BlockStatus >= 0)
	{
	    if(!vw->vw_BlockStatus)
		blk = 'B';
	    else
		blk = 'b';
	}
	else
	    blk = 0;
	freestring(vw->vw_LastTitle);
	sprintf(fmtbuff, "%s%lc (%ld,%ld) %ld line(s) %lc%lc%lc%lc%ld",
	    (LONG)tx->tx_TitleName,
	    tx->tx_Changes ? (LONG)'+' : (LONG)'\0',
	    (LONG)vw->vw_CursorPos.pos_Col + 1,
	    vw->vw_CursorPos.pos_Line + 1,
	    tx->tx_NumLines,
	    blk,
	    vw->vw_Prefs.prf_AutoIndent ? 'A' : 0,
	    vw->vw_Prefs.prf_WordWrap ? 'W' : 0,
	    vw->vw_Prefs.prf_NoSnapshotWin ? 'N' : 0,
	    vw->vw_Prefs.prf_SaveTabs);
	vw->vw_LastTitle = savestring(fmtbuff);
	SetWindowTitles(vw->vw_Window, vw->vw_LastTitle, (UBYTE *)-1L);
    }
}

VOID
resettitle(VOID)
{
    CurrVW->vw_NonStdTitle = FALSE;
}

Local struct EasyStruct ezstruct =
{
    sizeof(struct EasyStruct),
    0,
    "jed request...",
    NULL,
    NULL,
};

LONG
ezreq(STRPTR bodyFmt, STRPTR gadFmt, LONG arg1, ...)
{
    ezstruct.es_TextFormat = bodyFmt;
    ezstruct.es_GadgetFormat = gadFmt;
    return(EasyRequestArgs(CurrVW->vw_Window, &ezstruct, NULL, &arg1));
}

/*
 * (req `bodyFmt' `gadFmt' args...)
 *
 * command to do a request, formatting is provided.
 * result is number of gadget pressed (starting at 1 for leftmost gadget and
 * incrementing by one, rightmost gadget is 0.
 */
VALUE *
cmd_req(LONG argc, VALUE *argv)
{
    if(TPLATE2(VTF_STRING, VTF_STRING))
    {
	LONG result, i, args[20];

	ezstruct.es_TextFormat = ARG1.val_Value.String;
	ezstruct.es_GadgetFormat = ARG2.val_Value.String;

	for(i = 0; (i < (argc - 2)) && (i < 20); i++)
	    args[i] = argv[i + 3].val_Value.Number;

	result = EasyRequestArgs(CurrVW->vw_Window, &ezstruct, NULL, args);
	setnumres(result);
    }
    return(&RES);
}

BOOL
setfont(VW *vw)
{
    struct TextAttr ta;
    struct TextFont *tf;

    ta.ta_Name = vw->vw_Prefs.prf_FontName;
    ta.ta_YSize = vw->vw_Prefs.prf_FontSize;
    ta.ta_Style = FS_NORMAL;
    ta.ta_Flags = 0;

    if(tf = OpenDiskFont(&ta))
    {
	if(tf->tf_Flags & FPF_PROPORTIONAL)
	{
	    CloseFont(tf);
	    return(FALSE);
	}
	SetFont(vw->vw_Rp, tf);
	if(vw->vw_Font)
	    CloseFont(vw->vw_Font);
	vw->vw_Font = tf;
	updatedimensions(vw);
	return(TRUE);
    }
    return(FALSE);
}

VALUE *
cmd_rename(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
    {
	TX *tx = CurrVW->vw_Tx;
	STRPTR newn, newt;
	BOOL rc = FALSE;
	if(newn = savestring(ARG1.val_Value.String))
	{
	    if(newt = (*ARG1.val_Value.String ? savestring(FilePart(ARG1.val_Value.String)) : savestring("Unititled")))
	    {
		freestring(tx->tx_TitleName);
		freestring(tx->tx_FileName);
		tx->tx_FileName = newn;
		tx->tx_TitleName = newt;
		resetslptxtitles(tx);
		rc = TRUE;
	    }
	}
	if(!rc)
	    settitle(NoMemMsg);
	setnumres(rc);
    }
    return(&RES);
}

VALUE *
cmd_changes(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_NUMBER))
    {
	TX *tx = CurrVW->vw_Tx;
	setnumres(tx->tx_Changes);
	tx->tx_Changes = ARG1.val_Value.Number;
    }
    return(&RES);
}

/*
 * (position left top width height)
 */
VALUE *
cmd_position(LONG argc, VALUE *argv)
{
    if(TPLATE4(VTF_NUMBER, VTF_NUMBER, VTF_NUMBER, VTF_NUMBER))
    {
	VW *vw = CurrVW;
	if(!vw->vw_Sleeping)
	{
	    ChangeWindowBox(vw->vw_Window, ARG1.val_Value.Number, ARG2.val_Value.Number, ARG3.val_Value.Number, ARG4.val_Value.Number);
	    vw->vw_DeferRefresh = 1;
	}
	else
	{
	    vw->vw_OldDimensions[0] = ARG1.val_Value.Number;
	    vw->vw_OldDimensions[1] = ARG2.val_Value.Number;
	    vw->vw_OldDimensions[2] = ARG3.val_Value.Number;
	    vw->vw_OldDimensions[3] = ARG4.val_Value.Number;
	}
	setnumres(TRUE);
    }
    return(&RES);
}

/*
 * Used when the name of a TX is changed. All sleeping views have their title
 * display updated.
 */
VOID
resetslptxtitles(TX *tx)
{
    VW *vw = (VW *)tx->tx_Views.mlh_Head;
    while(vw->vw_Node.mln_Succ)
    {
	if(vw->vw_Sleeping)
	    SetWindowTitles(vw->vw_Window, tx->tx_TitleName, (UBYTE *)~0);
	vw = (VW *)vw->vw_Node.mln_Succ;
    }
}
