
/*
 * MAIN.C
 *
 *      (C)Copyright 1987 by Matthew Dillon, All Rights Reserved.
 *
 */

#include "defs.h"
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <libraries/asl.h>
#include <clib/asl_protos.h>
#include <graphics/gfxbase.h>
#include <graphics/rastport.h>
#include <clib/reqtools_protos.h>
#include <libraries/reqtools.h>

Prototype short Xsize, Ysize;
Prototype short XTbase, YTbase;
Prototype short Rows, Columns;
Prototype short Xbase, Ybase;
Prototype short Xpixs, Ypixs;

Prototype ubyte *av[];
Prototype char Wdisable;
Prototype struct FileRequester *FReq;

Prototype void ipchandler (void);
Prototype void initipc (void);
Prototype void do_ipc (void);
Prototype void do_iconify (void);
Prototype void do_tomouse (void);
Prototype void iconify (void);
Prototype void uniconify (void);
Prototype void do_newwindow (void);
Prototype void do_openwindow(void);
Prototype struct Window *TOpenWindow (struct NewWindow *);
Prototype struct Window *opensharedwindow (struct NewWindow *);
Prototype void closesharedwindow (struct Window *);
Prototype int getyn (char *);
Prototype void title (char *);
Prototype void window_title (void);
Prototype void set_window_params (void);
Prototype void exiterr (char *);
Prototype int breakcheck (void);
Prototype void breakreset (void);
Prototype void do_resize (void);
Prototype int ops (char **, int);
Prototype char *geoskip(char *, int *, int *);
Prototype void GeometryToNW(char *, struct NewWindow *);
Prototype void prop_adj(void);
Prototype struct Gadget *add_prop(struct Window *);
Prototype void rest_prop(ED *);
Prototype int new_top(void);

typedef struct Process      PROC;
typedef struct WBStartup    WBS;
typedef struct DiskObject   DISKOBJ;

#define IDCMPFLAGS   CLOSEWINDOW|NEWSIZE|RAWKEY|MOUSEBUTTONS|ACTIVEWINDOW|MOUSEMOVE|MENUPICK|GADGETUP

struct NewWindow Nw = {
   0, 1, 0  , 0  , -1, -1,  /*  width, height filled in by program */
   IDCMPFLAGS,
   ACTIVATE|WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|NOCAREREFRESH|RMBTRAP,
   NULL, NULL, (ubyte *)"   WAIT   ",
   NULL, NULL,
   32, 32, -1, -1,
   WBENCHSCREEN
};

/* prop gadget stuff (TJM) */
#ifndef max
#define max(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif

/* so we can malloc it all at once ... */
struct PropGadget {
    struct Gadget g;
    struct PropInfo p;
    struct Image i;
} PropTemp = {
  { NULL, -13, 0, 10, 0, GFLG_RELRIGHT|GFLG_RELHEIGHT,
    GACT_RIGHTBORDER|GACT_RELVERIFY,
    GTYP_PROPGADGET
  },
} ;

static char noadj;      /* for blocking software adj. of prop gad when intuition (user) already did it */

/* end of Prop stuff */

static char DoIconify;

short Sharedrefs;
short Oldtlen = 999;      /*  Old Title Length    */
struct MsgPort *Sharedport;
struct FileRequester *FReq;
static DISKOBJ *Do;
WBS     *Wbs;

short Xsize,  Ysize;            /* font character sizes        */
short Rows,  Columns;           /* character rows/cols available       */
short Xbase,  Ybase;            /* offset pixel base for display       */
short XTbase,YTbase;            /* used for text display               */
short Xpixs,  Ypixs;            /* actual # X/Y pixels available       */
short Mx, My;

ubyte *av[8];
char Quitflag;
char Overide;
char Wdisable = 1;              /* Disable icon save                   */
char MShowTitle, MForceTitle;

#ifdef NOTDEF
PORT *IPCPort;

PORT *IPCRPort;
#endif

long Mask,RMask;

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *IconBase;
struct Library *AslBase;

extern int Enable_Abort;

#if AREXX
#include <rexx/rxslib.h>

extern short InRxCmd;
extern struct MsgPort *RexxPort;
extern struct RxsLib *RexxSysBase;
#endif

#ifdef LATTICE
int CXBRK(void)
{
 return(0);
}
#endif

static char *Ffile;

int main(int, char **);
void mybrk(void);

int
wbmain(WBS *wbs)
{
    return(main(0, (char **)wbs));
}

int
main(int mac, char **mav)
{
    char nf, ni;            /*  # files on command line     */
    char notdone;           /*  for endless loop            */
    char iawm = 0;          /*  overide mouse buttons       */
    char dontwait = 0;      /*  don't wait for a message    */
    short i;
    PROC *proc = (PROC *)FindTask(NULL);
    BPTR origlock, oldlock;

#ifndef LATTICE
    onbreak(mybrk);
#endif

    fclose(stdin);
    /*fclose(stdout);*/     /*  assume person will run >nil:    */
    fclose(stderr);         /*  close stderr & console ref. */
    origlock = CurrentDir(DupLock((BPTR)proc->pr_CurrentDir));
    NewDME = 0;

    NewList((LIST *)&DBase);
    NewList((LIST *)&PBase);
    IntuitionBase = (struct IntiutionBase *)OpenLibrary("intuition.library", 0);
    GfxBase =       (struct GfxBase *)OpenLibrary("graphics.library", 0);
    if (IntuitionBase == NULL || GfxBase == NULL)
        exiterr("cannot open intuition or graphics library");

    if (AslBase = OpenLibrary("asl.library", 0))
        FReq = AllocAslRequest(ASL_FileRequest, NULL);

    if (ReqToolsBase = (struct ReqToolsBase *)OpenLibrary("reqtools.library",37))
        RFReq = rtAllocRequestA (RT_FILEREQ, NULL);

    init_command();

    Pagejump = 80;          /* for Propgad & pageup/down */

    DoIconify = 0;

    String  = (char *)malloc(1);        /*  initialize scanf variable   */
    *String = 0;

    if (mac == 0) {             /*  WORKBENCH STARTUP   */
        Wdisable = 0;           /*  allow icon save     */
        Wbs = (WBS *)mav;
        IconBase = OpenLibrary("icon.library", 0);
        if (IconBase == NULL) {
            if(FReq)
                FreeAslRequest(FReq);
            if(AslBase)
                CloseLibrary(AslBase);
            if(RFReq)
                rtFreeRequest(RFReq);
            if(ReqToolsBase)
                CloseLibrary((struct Library *)ReqToolsBase);
            exiterr("unable to open icon library");
        }
    }
    resethash();

    if (Wbs) {
        if (Wbs->sm_ArgList[0].wa_Lock) {
            BPTR savelock = CurrentDir((BPTR)Wbs->sm_ArgList[0].wa_Lock);
            if (Do = GetDiskObject(Wbs->sm_ArgList[0].wa_Name)) {
                ops(Do->do_ToolTypes, 1);
                FreeDiskObject(Do);
            }
            CurrentDir(savelock);
        }
        nf = Wbs->sm_NumArgs - 1;
        mac = 99;
    } else {
        nf = ops(mav+1, 0);
    }

#if AREXX
    {
        mountrequest(0);
        openrexx();     /*   do this after the last possible call to exiterr() */
        mountrequest(1);
    }
#endif

    for (ni = 0, i = 1; i < mac; ++i) {
        char *str;
        DISKOBJ *dso;
        if (Wbs) {
            if (i > nf)
                break;
            str = Wbs->sm_ArgList[i].wa_Name;
            UnLock(CurrentDir(DupLock((BPTR)Wbs->sm_ArgList[i].wa_Lock)));
            if (dso = GetDiskObject(Wbs->sm_ArgList[i].wa_Name)) {
                ops(dso->do_ToolTypes, 1);
                FreeDiskObject(dso);
            }
        } else {
            str = mav[i];
            if (*str == '-')
                continue;
        }
        if(NewDME) {
            do_newwindow();
            ++ni;
            av[0] = (ubyte *)"newfile";
            av[1] = (ubyte *)str;
            do_edit();
            MForceTitle = 1;
            window_title();
            if(DoIconify && i + 1 < mac)
                do_iconify();
        }
        else {
            CurrentDir(oldlock = CurrentDir(NULL));
            if (!getpathto(oldlock,"",Deline))
                strcpy(Deline,"SYS:");
            sprintf(Current,"\"'newwindow cd (%s) newfile (%s)%s'\"",Deline,str,DoIconify?" iconify":"");
            do_rrexx(Current);
        }
    }
    if (nf == 0) {                  /* no files to edit */
        if(NewDME)
            do_newwindow();
        else {
            if(DoIconify)
                do_rrexx("\"'newwindow iconify'\"");
            else
                do_rrexx("\"'newwindow'\"");
        }
    }
    if(NewDME && Ep) {
        mountrequest(0);
        av[0] = NULL;
        av[1] = (ubyte *)"s:.edrc";
        do_source();
        av[0] = NULL;
        av[1] = (ubyte *)((Ffile) ? Ffile : ".edrc");
        do_source();
        mountrequest(1);
        {                       /*  1.29c   */
            ED *ep;
            ED *eb = Ep;
            if (eb) {
                for (ep = (ED *)eb->Node.mln_Succ; ep->Node.mln_Succ; ep = (ED *)ep->Node.mln_Succ) {
                    ep->Tabstop = eb->Tabstop;
                    ep->Margin  = eb->Margin;
                    ep->Insertmode = eb->Insertmode;
                    ep->IgnoreCase = eb->IgnoreCase;
                    ep->Wordwrap   = eb->Wordwrap;
                    if (eb->Font) {
                        ep->Font = eb->Font;
                        ++eb->Font->tf_Accessors;
                    }
                }
            }
        }
        if(DoIconify)
            do_iconify();
        title("DME V1.46 \251Copyright 1988-1990 by Matthew Dillon,  All Rights Reserved             ");
        Mask |= 1 << Ep->Win->UserPort->mp_SigBit;
#if AREXX
        if(RexxSysBase)
            RMask = 1 << RexxPort->mp_SigBit;
#endif
loop:
        if (!Ep->iconmode)
            text_cursor(1);
        for (notdone = 1; RxBlock || (!Quitflag && notdone);) {
            char mmove = 0;
            short mqual;
#if AREXX
            unsigned long waitwas;
#endif

            if (!Ep->iconmode)
                window_title();
            if (dontwait) {
                --dontwait;
            } else {
#if AREXX
                if(Comlinemode)
                    waitwas = Wait(Mask);
                else if(!RxBlock)
                    waitwas = Wait(Mask|RMask);
                else
                    waitwas = Wait(RMask);
#else
                Wait(Mask);
#endif
            }

            /*
            *  NOTE: due to operation of breakcheck(), the userport signal
            *  may not be set even if there are messages pending.
            */

            if(waitwas & Mask) {
                IMESS *im, pm;

                while (im = (IMESS *)GetMsg(Ep->Win->UserPort)) {
                    Msgchk = 1;
                    Abortcommand = 0;
                    memcpy(&pm,im,sizeof(pm));
                    Mx = im->MouseX;
                    My = im->MouseY;

                    ReplyMsg((MSG *)im); /* moved up here to prevent crashing */

                    if (pm.IDCMPWindow != Ep->Win) {
                        Overide = 0;
                        if (Comlinemode)
                            escapecomlinemode();
                        text_sync();
                        MShowTitle = 0;
                        if (!Ep->iconmode)
                            window_title();
                        if (text_switch(pm.IDCMPWindow) == 0) {
                            continue;
                        }
                    }
                    switch(pm.Class) {
                    case NEWSIZE:
                        if (!Ep->iconmode) {
                            if (Comlinemode)
                                escapecomlinemode();
                            set_window_params();
                            if (!text_sync())
                                text_redisplay();
                            text_cursor(1);
                        }
                        break;
                    case MOUSEBUTTONS:
                        switch(pm.Code) {
                        case SELECTDOWN:
                        case MENUDOWN:
                        case MIDDLEDOWN:
                            if (Ep->iconmode || iawm) {
                                uniconify();
                                text_cursor(1);
                                break;
                            }
                            Forbid();
                            Ep->Win->Flags |= REPORTMOUSE;
                            Permit();
                            uniconify();
                            text_cursor(0);
                            keyctl(NULL, pm.Code|0x80, pm.Qualifier);
                            text_cursor(1);
                            break;
                        case SELECTUP:
                        case MENUUP:
                        case MIDDLEUP:
                            Forbid();
                            Ep->Win->Flags &= ~REPORTMOUSE;
                            Permit();
                            text_cursor(0);
                            keyctl(NULL, pm.Code, pm.Qualifier); /* up == |0x80 */
                            text_cursor(1);
                            break;
                        }
                        break;
                    case RAWKEY:
                        if ((pm.Code & 0x80) == 0) {
                            /*  Handled in command interpreter.
                            if (Ep->iconmode) {
                                uniconify();
                                break;
                            }
                            */
                            text_cursor(0);
                            keyctl(&pm, pm.Code, pm.Qualifier);
                            text_cursor(1);
                        }
                        break;
                    case MENUPICK:
                        {
                            char *str = menu_cmd(pm.Code);
                            if (str) {
                                str = strcpy(malloc(strlen(str)+1), str);
                                text_cursor(0);
                                do_command(str);
                                free(str);
                                text_cursor(1);
                            }
                        }
                        break;
                    case CLOSEWINDOW:
                        if (Comlinemode)
                            escapecomlinemode();
                        text_sync();
                        notdone = 0;
                        break;
                    case ACTIVEWINDOW:
                        break;
                    case MOUSEMOVE:
                        mmove = 1;
                        mqual = pm.Qualifier;
                        break;
                    case GADGETUP:
                        if (!Ep->iconmode) {
                            int newtop = new_top();

                            noadj = 1;              /* block software prop refresh */
                            if (Comlinemode)
                                escapecomlinemode();
                            if(newtop != Ep->Topline) {
                                text_sync();
                                Ep->Line += newtop - Ep->Topline;
                                Ep->Topline = newtop;
                                text_load();
                                if (!text_sync())
                                    text_redisplay();
                            }
                            noadj = 0;              /* reallow software prop refresh */
                            text_cursor(1);
                        }
                        break;
                    }
                    if (!RxBlock && (notdone == 0 || Quitflag)) {
                        dontwait = 2;
                        goto boom;
                    }
                }
            }

#if AREXX
            if(RexxSysBase && (waitwas & RMask)) {
                text_cursor(0);
                Process_Rexx();
                text_cursor(1);
                if (Quitflag && !RxBlock) {
                    dontwait = 2;
                    goto boom;
                }
            }
#endif AREXX

            iawm = 0;
            if (mmove) {
                uniconify();
                mmove = 0;
                text_cursor(0);
                keyctl(NULL, QMOVE, mqual);
                text_cursor(1);
            }
#ifdef NOTDEF
            closesharedwindow(NULL);  /* removed by TJM */
#endif
        }
boom:
        text_sync();
        if (Ep->Modified && !Overide) {
            uniconify();
            Overide = 1;
            title("*** File has been modified ***");
            Quitflag = 0;
            goto loop;
        }
        SetWindowTitles(Ep->Win, "", (char *)-1);
        {
            WIN *win = Ep->Win;
            struct Gadget *g = Ep->PropGad;
            text_uninit();
            closesharedwindow(win);
            if(g)
                free(g);
        }
        if (Ep) {
            Quitflag = 0;
            if (!Ep->iconmode)
                set_window_params();
            text_load();
            MShowTitle = 0;
            goto loop;
        }
    }
#ifdef NOTDEF
    closesharedwindow(NULL); /* removed TJM */
#endif
#if AREXX
    closerexx();
#endif
    UnLock(CurrentDir(origlock));
#ifdef NOTDEF
    if (IPCRPort) /* no IPC port to begin with ... */
        DeletePort(IPCRPort);
#endif
    if (IconBase)
        CloseLibrary((void *)IconBase);
    if (FReq)
        FreeAslRequest(FReq);
    if (AslBase)
        CloseLibrary(AslBase);
    if(RFReq)
        rtFreeRequest(RFReq);
    if(ReqToolsBase)
        CloseLibrary((struct Library *)ReqToolsBase);
    if (GfxBase)
        CloseLibrary((struct Library *)GfxBase);
    if (IntuitionBase)
        CloseLibrary((struct Library *)IntuitionBase);

    IconBase = NULL;
    GfxBase = NULL;
    IntuitionBase = NULL;

    dealloc_hash();
    /* at this point, exiterr("no mem") would be nice if windows weren't opened.. */
    return(0);
}

void
mybrk()
{
    return;
}

void
do_iconify()
{
    text_sync();
    if (!Comlinemode)
        iconify();
}

void
do_tomouse()
{
    text_position((Mx-Xbase)/Xsize, (My-Ybase)/Ysize);
}

/*
 *  New iconify() routine by fgk.
 */

void
iconify()
{
    WIN *newwin;
    ED *ep = Ep;
    WIN *win = ep->Win;

    struct IntuiText itxt;              /* To find width of prop fonts */

    itxt.ITextFont = Ep->Win->WScreen->Font;    /* Init */
    itxt.NextText = NULL;

    if (!ep->iconmode) {
        ep->Winx      = win->LeftEdge;
        ep->Winy      = win->TopEdge;
        ep->Winwidth  = win->Width;
        ep->Winheight = win->Height;

        /*Nw.Height = win->RPort->TxHeight + 3;*/


        if(Ep->Win->WScreen->Font != NULL)
            Nw.Height = Ep->Win->WScreen->Font->ta_YSize + 3;   /* height */
        else
            Nw.Height = GfxBase->DefaultFont->tf_YSize + 3;

        /*Nw.Width  = 20 + 5*8 + strlen(ep->Name) * (win->RPort->TxWidth + win->RPort->TxSpacing);*/

        itxt.IText = ep->Name;

        /* pretending spaces are always 8 */
        Nw.Width  = 20 + 5*8 + IntuiTextLength(&itxt);          /* width */


        Nw.LeftEdge= ep->IWinx;
        Nw.TopEdge = ep->IWiny;

        if (Nw.LeftEdge + Nw.Width > win->WScreen->Width)   /* keep in bounds */
            Nw.LeftEdge = win->WScreen->Width - Nw.Width;

        if (Nw.TopEdge + Nw.Height > win->WScreen->Height)
            Nw.TopEdge = win->WScreen->Height - Nw.Height;

        Nw.Title = ep->Wtitle;

        Nw.Flags &= ~(WINDOWSIZING|WINDOWDEPTH|ACTIVATE);

        if (ep->Modified) {     /* no CLOSE */
            Nw.Width -= 3*8;
            Nw.Flags &= ~WINDOWCLOSE;
        }

       /******* Nw.Flags |= BORDERLESS;*******/

        Nw.DetailPen = ep->BGPen;
        Nw.BlockPen  = ep->FGPen;
        if (win->Flags & WINDOWACTIVE)      /*  KTS */
            Nw.Flags |= ACTIVATE;
        sprintf(ep->Wtitle, "%s     ", ep->Name);

        if (newwin = opensharedwindow(&Nw)) {
            closesharedwindow(win);
            Nw.BlockPen = -1;
            ep->iconmode = 1;
            ep->Win = newwin;
        }

        Nw.Flags |= WINDOWSIZING|WINDOWDEPTH|WINDOWCLOSE|ACTIVATE;

        Nw.Flags &= ~BORDERLESS;
    }
}

void
uniconify()
{
    ED *ep = Ep;
    WIN *win = ep->Win;
    WIN *newwin;
    RP *rp;

    if (ep->iconmode) {
        ep->IWinx = win->LeftEdge;
        ep->IWiny = win->TopEdge;
        Nw.LeftEdge = ep->Winx;
        Nw.TopEdge  = ep->Winy;
        Nw.Width    = ep->Winwidth;
        Nw.Height   = ep->Winheight;
        Nw.Title    = ep->Wtitle;
        Nw.DetailPen = ep->BGPen;
        Nw.BlockPen  = ep->FGPen;

        if (newwin = opensharedwindow(&Nw)) {
            closesharedwindow(win);
            win= ep->Win = newwin;
            rp = win->RPort;

            menu_strip(win);
            if (ep->Font)
                SetFont(rp, ep->Font);
            set_window_params();
            rest_prop(ep);
            if (!text_sync())
                text_redisplay();
            /** text_cursor(1); **/
            MShowTitle = 0;
            window_title();
            ep->iconmode = 0;
        }
    }
}


void
do_newwindow()
{
    WIN *win;

    if (Ep)
        text_sync();
    Nw.Title = (ubyte *)"    OK    ";

    if (text_init(Ep, NULL, &Nw)) {
        if (win = opensharedwindow(&Nw)) {
            menu_strip(win);
            Ep->Win = win;
            set_window_params();
            Ep->PropGad = add_prop(win);
            text_load();
        } else {
            text_uninit();
        }
    }
}

/*
 *  openwindow with geometry specification.  Negative number specify
 *  relative-right / relative-left (leftedge & topedge), or relative-width /
 *  relative height (width & height).
 *
 *      <leftedge><topedge><width><height>
 *
 *  Example:    +10+10-20-20    Open window centered on screen 10 pixels
 *                              from the border on all sides.
 */

void
do_openwindow()
{
    WIN *win;

    if (Ep)
        text_sync();
    Nw.Title = (ubyte *)"    OK    ";

    if (text_init(Ep, NULL, &Nw)) {
        GeometryToNW(av[1], &Nw);
        if (win = opensharedwindow(&Nw)) {
            menu_strip(win);
            Ep->Win = win;
            set_window_params();
            Ep->PropGad = add_prop(win);
            text_load();
        } else {
            text_uninit();
        }
    }
}


WIN *
TOpenWindow(nw)
struct NewWindow *nw;
{
    WIN *win;

    while ((win = OpenWindow(nw)) == NULL) {
        if (nw->Width < 50 && nw->Height < 50)
            break;
        if(nw->Width >= 50)
            nw->Width -= 10;
        if(nw->Height >= 50)
            nw->Height-= 10;
    }
    return(win);
}


WIN *
opensharedwindow(nw)
struct NewWindow *nw;
{
    WIN *win;

    if (Sharedport)
        nw->IDCMPFlags = NULL;
    else
        nw->IDCMPFlags = IDCMPFLAGS;
    win = TOpenWindow(nw);
    if (win) {
        long xend = win->Width - win->BorderRight - 1;
        long yend = win->Height- win->BorderBottom - 1;
        if (Sharedport) {
            win->UserPort = Sharedport;
            ModifyIDCMP(win, IDCMPFLAGS);
        } else {
            Sharedport = win->UserPort;
        }
        ++Sharedrefs;
        if (xend > win->BorderLeft && yend > win->BorderTop) {
            SetAPen(win->RPort, nw->DetailPen);
            RectFill(win->RPort, win->BorderLeft, win->BorderTop, xend, yend);
            SetAPen(win->RPort, nw->BlockPen);
        }
    }
    return(win);
}

/* the following function straight from RKM by TJM */
static void StripIntuiMessages(struct MsgPort *,struct Window *);

static void
StripIntuiMessages(struct MsgPort *mp,struct Window  *win)
{
    struct IntuiMessage *msg, *succ;

    msg = (struct IntuiMessage *)(mp->mp_MsgList.lh_Head);

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

/* modifed TJM to close win's immediately using CloseWindowSafely from RKM */
void
closesharedwindow(win)
WIN *win;
{
    if (win) {
        SetWindowTitles(win, "", (char *)-1);
        ClearMenuStrip(win);

        Forbid();

        StripIntuiMessages(win->UserPort,win);
        if(--Sharedrefs)
            win->UserPort = NULL;
        else
            Sharedport = NULL;
        ModifyIDCMP(win,0);

        Permit();

        CloseWindow(win);

    } /* else something is very wrong.. */
}
#ifdef NOTDEF
void
closesharedwindow(win)
WIN *win;
{
    static WIN *wunlink = NULL;
    char notoktoclosenow = 0; /* a very odd and apparently useless variable... TJM */

    if (win) {
        SetWindowTitles(win, "", (char *)-1);
        ClearMenuStrip(win);
        Forbid();
        win->UserPort = NULL;
        ModifyIDCMP(win, REQCLEAR);     /* NEVER occurs -- I think (TJM)  changed from GADGETUP which could be from prop.*/

        notoktoclosenow = 1;

        Permit();
        if (notoktoclosenow) {
            win->UserData = (char *)wunlink;
            wunlink = win;
        } else {
            /* the following copied from RKM by TJM */
            Forbid();
            StripIntuiMessages(win->UserPort,win);
            win->UserPort = NULL;
            ModifyIDCMP(win,0);
            Permit();

            CloseWindow(win);
        }
        --Sharedrefs;
    } else {
        if (Sharedrefs == 0 && Sharedport) {
            DeletePort(Sharedport);
            Sharedport = NULL;
        }
        for (win = wunlink; win; win = wunlink) {
            wunlink = (WIN *)win->UserData;

            /* the following copied from RKM by TJM */
            Forbid();
            StripIntuiMessages(win->UserPort,win);
            win->UserPort = NULL;
            ModifyIDCMP(win,0);
            Permit();

            CloseWindow(win);
        }
        wunlink = NULL;
    }
}
#endif


getyn(text)
char *text;
{
    int result;
    ITEXT *body, *pos, *neg;

    body = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
    pos  = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
    neg  = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
    clrmem(body, sizeof(ITEXT));
    clrmem(pos , sizeof(ITEXT));
    clrmem(neg , sizeof(ITEXT));
    body->BackPen = pos->BackPen = neg->BackPen = 1;
    body->DrawMode= pos->DrawMode= neg->DrawMode= AUTODRAWMODE;
    body->LeftEdge = 10;
    body->TopEdge  = 12;
    body->IText    = (ubyte *)text;
    pos->LeftEdge = AUTOLEFTEDGE;
    pos->TopEdge = AUTOTOPEDGE;
    pos->IText = (ubyte *)"OK";
    neg->LeftEdge = AUTOLEFTEDGE;
    neg->TopEdge = AUTOTOPEDGE;
    neg->IText = (ubyte *)"CANCEL";
    result = AutoRequest(Ep->Win,body,pos,neg,0,0,320,58);
    FreeMem(body, sizeof(ITEXT));
    FreeMem(pos , sizeof(ITEXT));
    FreeMem(neg , sizeof(ITEXT));
    return(result);
}

void
title(buf)
char *buf;
{
    SetWindowTitles(Ep->Win, buf, (char *)-1);
    Oldtlen = 999;
    MShowTitle = 3;
}

void
window_title()
{
    int len, maxlen;

    if (memoryfail) {
        title(" -- NO MEMORY -- ");
        memoryfail = 0;
        text_redisplay();
    }
    if (MForceTitle) {
        MShowTitle = 0;
        MForceTitle = 0;
    }
    if (MShowTitle) {
        --MShowTitle;
        return;
    }
    {
        char *mod;
        FONT *oldfont;
        ED *ep = Ep;
        WIN *win = ep->Win;
        RP *rp = win->RPort;

        mod = (ep->Modified) ? " (modified)" : "          ";
        sprintf(ep->Wtitle, "%3ld/%-3ld %3ld %s%s  ", text_lineno(), text_lines(), text_colno()+1, text_name(), mod);
        if (!text_imode())
            strcat(ep->Wtitle, "Ovr ");
        len = strlen(ep->Wtitle);
        if (len < Columns && Columns < 128) {
            setmem(ep->Wtitle+len, Columns - len + 1, ' ');
            ep->Wtitle[Columns + 1] = 0;
        }

        /*
         *  Update title
         */

        if (IntuitionBase->LibNode.lib_Version >= 36) {
            SetWindowTitles(win, ep->Wtitle, (char *)-1);
        } else {
            oldfont = win->RPort->Font;
            SetFont(rp, win->WScreen->RastPort.Font);

            win->Title = ep->Wtitle;
            SetAPen(rp, ep->FGPen);
            SetBPen(rp, ep->TPen);
            Move(rp, 30, rp->Font->tf_Baseline+1);
            maxlen = (win->Width-96)/rp->Font->tf_XSize;
            if (maxlen < 0)
                maxlen = 0;
            if (len > maxlen)
                len = Oldtlen = maxlen;
            if (Oldtlen > maxlen)
                Oldtlen = maxlen;
            Text(rp, ep->Wtitle, len);      /*  No flash                    */
            while (Oldtlen - len >= (int)sizeof(Space)) {
                Text(rp, Space, sizeof(Space));
                Oldtlen -= sizeof(Space);
            }
            if (Oldtlen - len > 0)
                Text(rp, Space, Oldtlen - len);
            Oldtlen = len;                  /*  Oldtlen might have been <   */
            SetAPen(rp, ep->FGPen);
            SetBPen(rp, ep->BGPen);
            SetFont(rp, oldfont);
        }
    }
}

void
set_window_params()
{
    ED *ep = Ep;
    WIN *win = ep->Win;
    RP  *rp = win->RPort;

    Xsize = rp->Font->tf_XSize;
    Ysize = rp->Font->tf_YSize;
    Xbase = win->BorderLeft;
    Ybase = win->BorderTop;
    Xpixs   = win->Width - win->BorderRight - Xbase;
    Ypixs   = win->Height- win->BorderBottom- Ybase;
    Columns = Xpixs / Xsize;
    Rows    = Ypixs / Ysize;
    if (Columns <= 0)
        Columns = 1;
    if (Rows <= 0)
        Rows = 1;
    XTbase  =  Xbase;
    YTbase  =  Ybase + rp->Font->tf_Baseline;
    SetAPen(rp, ep->FGPen);
    SetBPen(rp, ep->BGPen);
}

void
exiterr(str)
char *str;
{
    if (Output()) {
        Write(Output(),str,strlen(str));
        Write(Output(),"\n",1);
    }
    exit(1);
}


/*
 *  Check break by scanning pending messages in the I stream for a ^C.
 *  Msgchk forces a check, else the check is only made if the signal is
 *  set in the I stream (the signal is reset).
 */

breakcheck()
{
    IMESS *im;
    WIN *win = Ep->Win;
    struct List *list = &win->UserPort->mp_MsgList;

    if (Msgchk || (SetSignal(0,0) & (1<<win->UserPort->mp_SigBit))) {
        Msgchk = 0;
        SetSignal(0,1<<win->UserPort->mp_SigBit);

        im = (IMESS *)list->lh_Head;
        Forbid();
        for (; im != (IMESS *)&list->lh_Tail; im = (IMESS *)im->ExecMessage.mn_Node.ln_Succ) {
            if (im->Class == RAWKEY && (im->Qualifier & 0xFB) == 0x08 &&
                im->Code == CtlC) {

                Permit();
                SetSignal(SIGBREAKF_CTRL_C,SIGBREAKF_CTRL_C);
                return(1);
            }
        }
        Permit();
    }
    return(0);
}

void
breakreset()
{
    SetSignal(0, SIGBREAKF_CTRL_C);
}

/*
 *  resize cols rows
 */

void
do_resize()
{
    WIN *win = Ep->Win;
    int cols = atoi(av[1]);
    int rows = atoi(av[2]);
    short width = (cols*win->RPort->Font->tf_XSize) + win->BorderLeft + win->BorderRight;
    short height= (rows*win->RPort->Font->tf_YSize) + win->BorderTop + win->BorderBottom;

    if (width < 16 || height < 16 ||
    width > win->WScreen->Width - win->LeftEdge ||
    height > win->WScreen->Height - win->TopEdge) {
        title ("window too big (try moving to upper left corner and retrying)");
        return;
    }
    SizeWindow(win, width - win->Width, height - win->Height);
    Delay(50*2);    /* wait 2 seconds */
}

ops(av, iswb)
char **av;
{
    short nonops;
    short i;
    long val;
    char *str;

    for (i = nonops = 0; str = av[i]; ++i) {
        if (iswb) {
            if (strncmp(str, "ARG", 3) == 0) {
                while (*str && *str != '-')
                    ++str;
            }
        }
        if (*str == '-') {
            val = atoi(str+2);
            switch(str[1]) {
            case 'f':
                Ffile = str+2;
                break;
#if AREXX
            case 'n':
                NewDME = 1;
                break;
#endif
            case 'b':
                /*SizeOveride = 1;*/
                break;
            case 't':
                /*Nwtopedge = val;*/
                break;
            case 'l':
                /*Nwleftedge= val;*/
                break;
            case 'w':
                /*SizeOveride = 1;*/
                /*Nwwidth   = val;*/
                break;
            case 'h':
                /*SizeOveride = 1;*/
                /*Nwheight  = val;*/
                break;
            case 'i':
                DoIconify = 1;
                break;
            }
        } else {
            ++nonops;
        }
    }
    return((int)nonops);
}

/*
 *  Convert geometry to nw params.
 */

char *
geoskip(ptr, pval, psgn)
char *ptr;
int *pval;
int *psgn;
{
    if (*ptr == '-')
        *psgn = -1;
    else
        *psgn = 1;
    if (*ptr == '-' || *ptr == '+')
        ++ptr;
    *pval = atoi(ptr);
    while (*ptr >= '0' && *ptr <= '9')
        ++ptr;
    return(ptr);
}

void
GeometryToNW(geo, nw)
char *geo;
struct NewWindow *nw;
{
    int n;
    int sign;
    struct Screen scr;

    GetScreenData(&scr, sizeof(scr), WBENCHSCREEN, NULL);

    if (*geo) {
        geo = geoskip(geo, &n, &sign);
        if (sign > 0)
            nw->LeftEdge = n;
        else
            nw->LeftEdge = scr.Width - n;
    }
    if (*geo) {
        geo = geoskip(geo, &n, &sign);
        if (sign > 0)
            nw->TopEdge = n;
        else
            nw->TopEdge = scr.Height - n;
    }
    if (*geo) {
        geo = geoskip(geo, &n, &sign);
        if (sign > 0)
            nw->Width = n;
        else
            nw->Width = scr.Width - nw->LeftEdge - n;
    }
    if (*geo) {
        geo = geoskip(geo, &n, &sign);
        if (sign > 0)
            nw->Height = n;
        else
            nw->Height = scr.Height - nw->TopEdge - n;
    }
}

/* prop gadget stuff (TJM) */

void rest_prop(ep)
ED *ep;
{
    if(!ep->PropGad)
        return;
    AddGadget(ep->Win,ep->PropGad,0);
    RefreshGList(ep->PropGad,ep->Win,NULL,1);
}

struct Gadget *add_prop(win)
struct Window *win;
{
    struct PropGadget *pg;

    if(!(pg = (struct PropGadget *)malloc(sizeof(*pg))))
        return NULL;

    memcpy(pg,&PropTemp,sizeof(PropTemp));
    pg->g.TopEdge = win->BorderTop + 1;
    pg->g.Height = -(win->BorderTop + 12);
    pg->p.Flags = AUTOKNOB|FREEVERT|PROPNEWLOOK;      /* PROPNEWLOOK is 2.0-dependent -- it == 0x0010 if you don't have 2.0 incl's */
    pg->p.HorizPot = pg->p.VertPot = pg->p.HorizBody = pg->p.VertBody = -1;
    pg->g.SpecialInfo = (APTR)&pg->p;
    pg->g.GadgetRender = &pg->i;

    AddGadget(win,&pg->g,0);
    RefreshGList(&pg->g,win,NULL,1);
    noadj = 0;      /* allow scroller refreshing */

    return &pg->g;
}


void
prop_adj()
{
    ULONG hidden = max(Ep->Lines - Rows, 0);
    ULONG VertBody, VertPot;
    ULONG topLine = min(Ep->Topline,hidden);
    ULONG Overlap = (Rows * (100 - Pagejump)) / 100;

    if(!Ep->PropGad || noadj)       /* block adjustment when already set by prop gad */
        return;

    /* all these damn castings... */
    if(hidden > 0) {
        VertBody = ((Rows - Overlap) * MAXBODY) / (Ep->Lines - Overlap);
        VertPot = (topLine * MAXPOT) / hidden;
    }
    else {
        VertBody = MAXBODY;
        VertPot = 0;
    }
    NewModifyProp(Ep->PropGad,Ep->Win,NULL,AUTOKNOB|FREEVERT|PROPNEWLOOK,MAXPOT,VertPot,MAXBODY,VertBody,1);
}

int new_top()
{
    struct PropInfo *Prop;
    int hidden = max(Ep->Lines - Rows, 0);

    Prop = (struct PropInfo *)(Ep->PropGad->SpecialInfo);

    return ((hidden * Prop->VertPot + MAXPOT/2) / MAXPOT);
}
