This is w.c in view mode; [Download] [Up]
/* Window system
Copyright (C) 1992 Joseph H. Allen
This file is part of JOE (Joe's Own Editor)
JOE is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 1, or (at your option) any later version.
JOE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
JOE; see the file COPYING. If not, write to the Free Software Foundation,
675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include "b.h"
#include "scrn.h"
#include "queue.h"
#include "main.h"
#include "poshist.h"
#include "blocks.h"
#include "zstr.h"
#include "w.h"
extern int dspasis; /* Set to display chars above 127 as-is */
extern int staen; /* 0 if top-most status line not displayed */
/* Count no. of main windows */
int countmain(t)
SCREEN *t;
{
int nmain=1;
W *m=t->curwin->main;
W *q;
for(q=t->curwin->link.next;q!=t->curwin;q=q->link.next)
if(q->main!=m)
{
++nmain;
m=q->main;
}
return nmain;
}
/* Redraw a window */
void wredraw(w)
W *w;
{
msetI(w->t->t->updtab+w->y,1,w->h);
}
/* Find first window in a group */
W *findtopw(w)
W *w;
{
W *x;
for(x=w;x->link.prev->main==w->main && x->link.prev!=w;x=x->link.prev);
return x;
}
/* Determine height of a window. Returns reqh if it is set, otherwise
* used fixed or hh scaled to the current screen size */
int geth(w)
W *w;
{
if(w->reqh) return w->reqh;
else
if(w->fixed) return w->fixed;
else return (((long)w->t->h-w->t->wind)*w->hh)/1000;
}
/* Set the height of a window */
void seth(w,h)
W *w;
{
long tmp;
w->reqh=h;
tmp=1000L*h;
w->hh=tmp/(w->t->h-w->t->wind)+(tmp%(w->t->h-w->t->wind)?1:0);
}
/* Determine height of a family of windows. Uses 'reqh' if it's set */
int getgrouph(w)
W *w;
{
W *x;
int h;
/* Find first window in family */
x=findtopw(w);
/* Add heights of all windows in family */
for(w=x, h=geth(w);
w->link.next!=x && w->link.next->main==x->main;
w=w->link.next, h+=geth(w));
return h;
}
/* Determine minimum height of a family */
int getminh(w)
W *w;
{
W *x;
int h;
x=findtopw(w);
for(w=x, h=(w->fixed?w->fixed:2);
w->link.next!=x && w->link.next->main==x->main;
w=w->link.next, h+=(w->fixed?w->fixed:2));
return h;
}
/* Find last window in a group */
W *findbotw(w)
W *w;
{
W *x;
for(x=w;x->link.next->main==w->main && x->link.next!=w;x=x->link.next);
return x;
}
/* Demote group of window to end of window list. Returns true if top window
was demoted */
int demotegroup(w)
W *w;
{
W *top=findtopw(w);
W *bot=findbotw(w);
W *next;
int flg=0;
for(w=top;w!=bot;w=next)
{
next=w->link.next;
if(w==w->t->topwin) flg=1, w->t->topwin=next;
else demote(W,link,w->t->topwin,w);
w->y= -1;
}
if(w==w->t->topwin) flg=1;
else demote(W,link,w->t->topwin,w);
w->y= -1;
return flg;
}
/* Find last window on the screen */
W *lastw(t)
SCREEN *t;
{
W *x;
for(x=t->topwin;x->link.next!=t->topwin && x->link.next->y>=0;x=x->link.next);
return x;
}
/* Create a screen object */
SCREEN *scr;
SCREEN *screate(scrn)
SCRN *scrn;
{
SCREEN *t=(SCREEN *)malloc(sizeof(SCREEN));
t->t=scrn;
t->w=scrn->co;
t->h=scrn->li;
t->topwin=0;
t->curwin=0;
t->wind=skiptop;
scr=t;
return t;
}
void sresize(t)
SCREEN *t;
{
SCRN *scrn=t->t;
W *w;
t->w=scrn->co;
t->h=scrn->li;
if(t->h-t->wind<FITHEIGHT) t->wind=t->h-FITHEIGHT;
if(t->wind<0) t->wind=0;
w=t->topwin; do
w->y= -1, w->w=t->w-1;
while(w=w->link.next, w!=t->topwin);
wfit(t);
updall();
}
void updall()
{
int y;
for(y=0;y!=scr->h;++y) scr->t->updtab[y]=1;
}
void scrins(b,l,n,flg)
B *b;
long l,n;
int flg;
{
W *w;
if(w=scr->topwin) do
if(w->y>=0)
{
if(w->object && w->watom->ins) w->watom->ins(w->object,b,l,n,flg);
}
while(w=w->link.next, w!=scr->topwin);
}
void scrdel(b,l,n,flg)
B *b;
long l,n;
int flg;
{
W *w;
if(w=scr->topwin) do
if(w->y>=0)
{
if(w->object && w->watom->del) w->watom->del(w->object,b,l,n,flg);
}
while(w=w->link.next, w!=scr->topwin);
}
/* Fit as many windows on the screen as is possible beginning with the window
* at topwin. Give any extra space which couldn't be used to fit in another
* window to the last text window on the screen. This function guarentees
* to fit on the window with the cursor in it (moves topwin to next group
* of windows until window with cursor fits on screen).
*/
static int doabort();
extern int dostaupd;
void wfit(t)
SCREEN *t;
{
int y; /* Where next window goes */
int left; /* Lines left on screen */
W *w; /* Current window we're fitting */
W *pw; /* Main window of previous family */
int req; /* Amount this family needs */
int adj; /* Amount family needs to be adjusted */
int flg=0; /* Set if cursor window was placed on screen */
int ret;
dostaupd=1;
tryagain:
y=t->wind; left=t->h-y; pw=0;
w=t->topwin; do
{
w->ny= -1;
w->nh=geth(w);
}
while((w=w->link.next)!=t->topwin);
/* Fit a group of windows on the screen */
w=t->topwin; do
{
req=getgrouph(w);
if(req>left) /* If group is taller than lines left */
adj=req-left; /* then family gets shorter */
else adj=0;
/* Fit a family of windows on the screen */
do
{
w->ny=y; /* Set window's y position */
if(!w->win) pw=w, w->nh-=adj; /* Adjust main window of the group */
if(!w->win && w->nh<2) while(w->nh<2) w->nh+=doabort(w->link.next,&ret);
if(w==t->curwin) flg=1; /* Set if we got window with cursor */
y+=w->nh; left-=w->nh; /* Increment y value by height of window */
w=w->link.next; /* Next window */
} while(w!=t->topwin && w->main==w->link.prev->main);
} while(w!=t->topwin && left>=FITHEIGHT);
/* We can't use extra space to fit a new family on, so give space to parent of
* previous family */
pw->nh+=left;
/* Adjust that family's children which are below the parent */
while((pw=pw->link.next)!=w) pw->ny+=left;
/* Make sure the cursor window got on the screen */
if(!flg)
{
t->topwin=findbotw(t->topwin)->link.next;
goto tryagain;
}
/* All of the windows are now on the screen. Scroll the screen to reflect what
* happened
*/
w=t->topwin; do
if(w->y>=0 && w->ny>=0)
if(w->ny>w->y)
{
W *l=pw=w;
while(pw->link.next!=t->topwin &&
(pw->link.next->y<0 || pw->link.next->ny<0 ||
pw->link.next->ny>pw->link.next->y))
{
pw=pw->link.next;
if(pw->ny>=0 && pw->y>=0) l=pw;
}
/* Scroll windows between l and w */
loop1:
if(l->ny>=0 && l->y>=0)
nscrldn(t->t,l->y,l->ny+Umin(l->h,l->nh),l->ny-l->y);
if(w!=l)
{
l=l->link.prev;
goto loop1;
}
w=pw->link.next;
}
else if(w->ny<w->y)
{
W *l=pw=w;
while(pw->link.next!=t->topwin &&
(pw->link.next->y<0 ||
pw->link.next->ny<0 ||
pw->link.next->ny<pw->link.next->y))
{
pw=pw->link.next;
if(pw->ny>=0 && pw->y>=0) l=pw;
}
/* Scroll windows between l and w */
loop0:
if(w->ny>=0 && w->y>=0)
nscrlup(t->t,w->ny,w->y+Umin(w->h,w->nh),w->y-w->ny);
if(w!=l)
{
w=w->link.next;
goto loop0;
}
w=pw->link.next;
}
else w=w->link.next;
else w=w->link.next;
while(w!=t->topwin);
/* Update current height and position values */
w=t->topwin; do
{
if(w->ny>=0)
{
if(w->object)
{
if(w->watom->move) w->watom->move(w->object,w->x,w->ny);
if(w->watom->resize) w->watom->resize(w->object,w->w,w->nh);
}
if(w->y== -1) msetI(t->t->updtab+w->ny,1,w->nh);
w->y=w->ny;
}
else w->y= -1;
w->h=w->nh;
w->reqh=0;
}
while(w=w->link.next, w!=t->topwin);
}
/* Goto next window */
int wnext(t)
SCREEN *t;
{
if(t->curwin->link.next!=t->curwin)
{
t->curwin=t->curwin->link.next;
if(t->curwin->y== -1) wfit(t);
return 0;
}
else return -1;
}
/* Goto previous window */
int wprev(t)
SCREEN *t;
{
if(t->curwin->link.prev!=t->curwin)
{
t->curwin=t->curwin->link.prev;
if(t->curwin->y== -1)
{
t->topwin=findtopw(t->curwin);
wfit(t);
}
return 0;
}
else return -1;
}
/* Grow window */
int wgrow(w)
W *w;
{
W *nextw;
/* If we're the last window on the screen, shrink the previous window */
if((w->link.next==w->t->topwin || w->link.next->y== -1) &&
w!=w->t->topwin)
return wshrink(w->link.prev->main);
/* Get to next variable size window */
for(nextw=w->link.next;nextw->fixed && nextw!=w->t->topwin;nextw=nextw->link.next);
/* Is it below us, on screen and big enough to take space from? */
if(nextw==w->t->topwin ||
nextw->y== -1 ||
nextw->h<=FITHEIGHT) return -1;
/* Increase this window's height */
seth(w,w->h+1);
/* Decrease next window's height */
seth(nextw,nextw->h-1);
/* Do it */
wfit(w->t);
return 0;
}
/* Shrink window */
int wshrink(w)
W *w;
{
W *nextw;
/* If we're the last window on the screen, grow the previous window */
if((w->link.next==w->t->topwin || w->link.next->y== -1) &&
w!=w->t->topwin)
return wgrow(w->link.prev->main);
/* Is this window too small already? */
if(w->h<=FITHEIGHT) return -1;
/* Get to window below us */
for(nextw=w->link.next;
nextw!=w->t->topwin && nextw->fixed;
nextw=nextw->link.next);
if(nextw==w->t->topwin) return -1;
/* Decrease the size of this window */
seth(w,w->h-1);
/* Increase the size of next window */
seth(nextw,nextw->h+1);
/* Do it */
wfit(w->t);
return 0;
}
/* Show all windows */
void wshowall(t)
SCREEN *t;
{
int n=0;
int set;
W *w;
/* Count no. of main windows */
w=t->topwin; do
if(!w->win) ++n;
while(w=w->link.next, w!=t->topwin);
/* Compute size to set each window */
if((set=(t->h-t->wind)/n)<FITHEIGHT) set=FITHEIGHT;
/* Set size of each variable size window */
w=t->topwin; do
if(!w->win)
{
int h=getminh(w);
if(h>=set) seth(w,2);
else seth(w,set-(h-2));
w->orgwin=0;
}
while(w=w->link.next, w!=t->topwin);
/* Do it */
wfit(t);
}
void wspread(t)
SCREEN *t;
{
int n=0;
W *w=t->topwin; do
if(w->y>=0 && !w->win) ++n;
while(w=w->link.next, w!=t->topwin);
if(!n)
{
wfit(t);
return;
}
if((t->h-t->wind)/n>=FITHEIGHT) n=(t->h-t->wind)/n;
else n=FITHEIGHT;
w=t->topwin; do
if(!w->win)
{
int h=getminh(w);
if(h>=n) seth(w,2);
else seth(w,n-(h-2));
w->orgwin=0;
}
while(w=w->link.next, w!=t->topwin);
wfit(t);
}
/* Show just one family of windows */
void wshowone(w)
W *w;
{
W *q=w->t->topwin; do
if(!q->win)
{
seth(q,w->t->h-w->t->wind-(getminh(q)-2));
q->orgwin=0;
}
while(q=q->link.next, q!=w->t->topwin);
wfit(w->t);
}
/* Create a window */
W *wcreate(t,watom,where,target,original,height,huh,notify)
SCREEN *t;
WATOM *watom;
W *where, *target, *original;
int height;
char *huh;
int *notify;
{
W *new;
if(height<1) return 0;
/* Create the window */
new=(W *)malloc(sizeof(W));
new->notify=notify;
new->t=t;
new->w=t->w-1;
seth(new,height);
new->h=new->reqh;
new->y= -1;
new->ny=0; new->nh=0;
new->x=0;
new->huh=huh;
new->orgwin=original;
new->watom=watom;
new->object=0;
new->msgb=0;
new->msgt=0;
/* Set window's target and family */
if(new->win=target)
{ /* A subwindow */
new->main=target->main;
new->fixed=height;
}
else
{ /* A parent window */
new->main=new;
new->fixed=0;
}
/* Get space for window */
if(original)
if(original->h-height<=2)
{
/* Not enough space for window */
free(new);
return 0;
}
else seth(original,original->h-height);
/* Create new keyboard handler for window */
if(watom->context) new->kbd=mkkbd(getcontext(watom->context));
else new->kbd=0;
/* Put window on the screen */
if(where) enquef(W,link,where,new);
else
{
if(t->topwin) enqueb(W,link,t->topwin,new);
else izque(W,link,new), t->curwin=t->topwin=new;
}
return new;
}
/* Abort group of windows */
static int doabort(w,ret)
W *w;
int *ret;
{
int amnt=geth(w);
W *z;
w->y= -2;
if(w->t->topwin==w) w->t->topwin=w->link.next;
loop:
z=w->t->topwin; do
{
if(z->orgwin==w) z->orgwin=0;
if((z->win==w || z->main==w) && z->y!= -2)
{
amnt+=doabort(z,ret);
goto loop;
}
}
while(z=z->link.next, z!=w->t->topwin);
if(w->orgwin) seth(w->orgwin,geth(w->orgwin)+geth(w));
if(w->t->curwin==w)
if(w->t->curwin->win) w->t->curwin=w->t->curwin->win;
else
if(w->orgwin) w->t->curwin=w->orgwin;
else w->t->curwin=w->link.next;
if(qempty(W,link,w))
{
leave=1;
amnt=0;
}
deque(W,link,w);
if(w->watom->abort && w->object)
{
*ret=w->watom->abort(w->object,MAXINT);
if(w->notify) *w->notify= -1;
}
else
{
*ret= -1;
if(w->notify) *w->notify= 1;
}
rmkbd(w->kbd);
free(w);
windie(w);
return amnt;
}
/* Abort a window and its children */
int wabort(w)
W *w;
{
SCREEN *t=w->t;
int ret;
if(w!=w->main)
{
doabort(w,&ret);
if(!leave) wfit(t);
}
else
{
doabort(w,&ret);
if(!leave)
{
if(lastw(t)->link.next!=t->topwin) wfit(t);
else wspread(t);
}
}
return ret;
}
/* Generate text with formatting escape sequences */
void genfmt(t,x,y,ofst,s,flg)
SCRN *t;
char *s;
{
int *scrn=t->scrn+y*t->co+x;
int atr=0;
int col=0;
int c;
while(c= *s++)
if(c=='\\')
switch(c= *s++)
{
case 'u': case 'U':
atr^=UNDERLINE;
break;
case 'i': case 'I':
atr^=INVERSE;
break;
case 'b': case 'B':
atr^=BOLD;
break;
case 'd': case 'D':
atr^=DIM;
break;
case 'f': case 'F':
atr^=BLINK;
break;
case 0: --s;
break;
default:
if(col++>=ofst)
{
outatr(t,scrn,x,y,c,atr);
++scrn;
++x;
}
break;
}
else if(col++>=ofst)
{
if(c=='\t') c=' ';
outatr(t,scrn,x,y,c,atr);
++scrn;
++x;
}
if(flg) eraeol(t,x,y);
}
/* Generate text: no formatting */
void gentxt(t,x,y,ofst,s,len,flg)
SCRN *t;
char *s;
{
int *scrn=t->scrn+y*t->co+x;
int col;
int c;
int a;
for(col=0;col!=len;++col)
if(col>=ofst)
{
c= (unsigned)s[col];
if(c=='\t') c=' ';
xlat(a,c);
outatr(t,scrn,x,y,c,a);
++scrn; ++x;
}
if(flg) eraeol(t,x,y);
}
/* Determine column width of string with format codes */
int fmtlen(s)
char *s;
{
int col=0;
while(*s)
{
if(*s=='\\')
switch(*++s)
{
case 'u': case 'i': case 'd': case 'f': case 'b':
case 'U': case 'I': case 'D': case 'F': case 'B':
++s; goto cont;
case 0:
--s;
}
++col; ++s;
cont:;
}
return col;
}
/* Return offset within format string which corresponds to a particular
column */
int fmtpos(s,goal)
char *s;
{
char *org=s;
int col=0;
while(*s && col!=goal)
{
if(*s=='\\')
switch(*++s)
{
case 'u': case 'i': case 'd': case 'f': case 'b':
case 'U': case 'I': case 'D': case 'F': case 'B':
++s; goto cont;
case 0:
--s;
}
++col; ++s;
cont:;
}
return s-org+goal-col;
}
/* Display a message and skip the next key */
static void mdisp(t,y,s)
SCRN *t;
char *s;
{
int ofst;
int len;
len=fmtlen(s);
if(len<=(t->co-1)) ofst=0;
else ofst=len-(t->co-1);
genfmt(t,0,y,ofst,s,1);
t->updtab[y]=1;
}
void msgout(w)
W *w;
{
SCRN *t=w->t->t;
if(w->msgb)
{
mdisp(t,w->y+w->h-1,w->msgb);
w->msgb=0;
}
if(w->msgt)
{
mdisp(t,w->y+( (w->h>1 && (w->y || !staen)) ? 1 : 0 ),w->msgt);
w->msgt=0;
}
}
/* Set temporary message */
char msgbuf[80];
void msgnw(w,s)
BASE *w;
char *s;
{
w->parent->msgb=s;
}
void msgnwt(w,s)
BASE *w;
char *s;
{
w->parent->msgt=s;
}
int urtn(b,k)
BASE *b;
{
if(b->parent->watom->rtn) return b->parent->watom->rtn(b,k);
else return -1;
}
int utype(b,k)
BASE *b;
{
if(b->parent->watom->type) return b->parent->watom->type(b,k);
else return -1;
}
/* Window user commands */
int uprevw(bw)
BASE *bw;
{
return wprev(bw->parent->t);
}
int unextw(bw)
BASE *bw;
{
return wnext(bw->parent->t);
}
int ugroww(bw)
BASE *bw;
{
return wgrow(bw->parent);
}
int ushrnk(bw)
BASE *bw;
{
return wshrink(bw->parent);
}
int uexpld(bw)
BASE *bw;
{
if(bw->parent->t->h-bw->parent->t->wind==getgrouph(bw->parent))
wshowall(bw->parent->t);
else wshowone(bw->parent);
return 0;
}
int uretyp(bw)
BASE *bw;
{
nredraw(bw->parent->t->t);
return 0;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.