home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
fish
/
text
/
editors
/
dme_441
/
src
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-24
|
20KB
|
949 lines
/*
* MAIN.C
*
* (C)Copyright 1987 by Matthew Dillon, All Rights Reserved.
*
*/
#include "defs.h"
#include <workbench/startup.h>
#include <workbench/workbench.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 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 ();
Prototype void do_openwindow();
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);
typedef struct Process PROC;
typedef struct WBStartup WBS;
typedef struct DiskObject DISKOBJ;
#define IDCMPFLAGS CLOSEWINDOW|NEWSIZE|RAWKEY|MOUSEBUTTONS|ACTIVEWINDOW|MOUSEMOVE|MENUPICK
extern void GeometryToNW(char *, struct NewWindow *);
extern WIN *OpenWindow();
extern void *OpenLibrary();
extern void *GetDiskObject();
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
};
short Sharedrefs;
short Oldtlen = 999; /* Old Title Length */
struct MsgPort *Sharedport;
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;
#endif
PORT *IPCRPort;
long Mask;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *IconBase;
extern int Enable_Abort;
static char *Ffile;
int main(int, char **);
int
wbmain(wbs)
WBS *wbs;
{
return(main(0, wbs));
}
int
main(mac, mav)
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;
short Code;
PROC *proc = (PROC *)FindTask(NULL);
BPTR origlock;
fclose(stdin);
/*fclose(stdout);*/ /* assume person will run >nil: */
fclose(stderr); /* close stderr & console ref. */
origlock = CurrentDir(DupLock((BPTR)proc->pr_CurrentDir));
NewList((LIST *)&DBase);
NewList((LIST *)&PBase);
IntuitionBase = OpenLibrary("intuition.library", 0);
GfxBase = OpenLibrary("graphics.library", 0);
if (IntuitionBase == (void *)NULL || GfxBase == (void *)NULL)
exiterr("cannot open intuition or graphics library");
init_command();
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)
exiterr("unable to open icon library");
}
#if AREXX
{
mountrequest(0);
openrexx(); /* do this after the last possible call to exiterr() */
mountrequest(1);
}
#endif
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);
}
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;
}
do_newwindow();
++ni;
av[0] = (ubyte *)"newfile";
av[1] = (ubyte *)str;
do_edit();
MForceTitle = 1;
window_title();
}
if (nf == 0) /* no files to edit */
do_newwindow();
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;
}
}
}
}
title("DME V1.43 \251Copyright 1988-1990 by Matthew Dillon, All Rights Reserved ");
Mask |= 1 << Ep->Win->UserPort->mp_SigBit;
loop:
if (!Ep->iconmode)
text_cursor(1);
for (notdone = 1; !Quitflag && notdone;) {
char mmove = 0;
short mqual;
if (!Ep->iconmode)
window_title();
if (dontwait) {
--dontwait;
} else {
Wait(Mask);
}
/*
* NOTE: due to operation of breakcheck(), the userport signal
* may not be set even if there are messages pending.
*/
{
IMESS *im;
while (im = (IMESS *)GetMsg(Ep->Win->UserPort)) {
Msgchk = 1;
Abortcommand = 0;
Code = im->Code;
if (im->IDCMPWindow != Ep->Win) {
Overide = 0;
if (Comlinemode)
escapecomlinemode();
text_sync();
MShowTitle = 0;
if (!Ep->iconmode)
window_title();
if (text_switch(im->IDCMPWindow) == 0) {
ReplyMsg((MSG *)im);
continue;
}
}
Mx = im->MouseX;
My = im->MouseY;
switch(im->Class) {
case NEWSIZE:
if (!Ep->iconmode) {
if (Comlinemode)
escapecomlinemode();
set_window_params();
if (!text_sync())
text_redisplay();
text_cursor(1);
}
break;
case MOUSEBUTTONS:
switch(Code) {
case SELECTDOWN:
case MENUDOWN:
if (Ep->iconmode || iawm) {
uniconify();
break;
}
Forbid();
Ep->Win->Flags |= REPORTMOUSE;
Permit();
uniconify();
text_cursor(0);
keyctl(NULL, im->Code|0x80, im->Qualifier);
text_cursor(1);
break;
case SELECTUP:
case MENUUP:
Forbid();
Ep->Win->Flags &= ~REPORTMOUSE;
Permit();
break;
}
break;
case RAWKEY:
if ((im->Code & 0x80) == 0) {
/* Handled in command interpreter.
if (Ep->iconmode) {
uniconify();
break;
}
*/
text_cursor(0);
keyctl(im, im->Code, im->Qualifier);
text_cursor(1);
}
break;
case MENUPICK:
{
char *str = menu_cmd(im);
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:
if (!Ep->iconmode)
iawm = 1;
break;
case MOUSEMOVE:
mmove = 1;
mqual = im->Qualifier;
break;
}
if (im)
ReplyMsg((MSG *)im);
if (notdone == 0 || Quitflag) {
dontwait = 2;
goto boom;
}
}
}
iawm = 0;
if (mmove) {
uniconify();
mmove = 0;
text_cursor(0);
keyctl(NULL, QMOVE, mqual);
text_cursor(1);
}
closesharedwindow(NULL);
}
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;
text_uninit();
closesharedwindow(win);
}
if (Ep) {
Quitflag = 0;
if (!Ep->iconmode)
set_window_params();
text_load();
MShowTitle = 0;
goto loop;
}
closesharedwindow(NULL);
#if AREXX
closerexx();
#endif
UnLock(CurrentDir(origlock));
if (IPCRPort)
DeletePort(IPCRPort);
if (IconBase)
CloseLibrary(IconBase);
if (GfxBase)
CloseLibrary(GfxBase);
if (IntuitionBase)
CloseLibrary(IntuitionBase);
IconBase = GfxBase = IntuitionBase = 0;
dealloc_hash();
return(0);
}
void
do_iconify()
{
text_sync();
if (!Comlinemode)
iconify();
}
void
do_tomouse()
{
text_position((Mx-Xbase)/Xsize, (My-Ybase)/Ysize);
}
void
iconify()
{
WIN *newwin;
ED *ep = Ep;
WIN *win = ep->Win;
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;
Nw.Width = 20 + 5*8 + strlen(ep->Name) * (win->RPort->TxWidth + win->RPort->TxSpacing);
if (ep->Modified)
Nw.Width -= 3*8;
Nw.LeftEdge= ep->IWinx;
Nw.TopEdge = ep->IWiny;
if (Nw.LeftEdge + Nw.Width > win->WScreen->Width)
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)
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();
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();
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();
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;
nw->Width -= 10;
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);
}
void
closesharedwindow(win)
WIN *win;
{
static WIN *wunlink;
char notoktoclosenow = 0;
if (win) {
SetWindowTitles(win, "", (char *)-1);
ClearMenuStrip(win);
Forbid();
win->UserPort = NULL;
ModifyIDCMP(win, GADGETUP); /* NEVER occurs */
notoktoclosenow = 1;
Permit();
if (notoktoclosenow) {
win->UserData = (char *)wunlink;
wunlink = win;
} else {
CloseWindow(win);
}
--Sharedrefs;
} else {
if (Sharedrefs == 0 && Sharedport) {
DeletePort(Sharedport);
Sharedport = NULL;
}
for (win = wunlink; win; win = wunlink) {
wunlink = (WIN *)win->UserData;
CloseWindow(win);
}
wunlink = NULL;
}
}
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
*/
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;
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;
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;
}
} 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;
}
}