|
|
1.1 root 1: #include <jerq.h>
2: #include <layer.h>
3: #include <font.h>
4: #include <queue.h>
5: #include <jerqproc.h>
6: #include <setup.h>
7: #include "frame/frame.h"
8: #include "../msgs.h"
9:
10: #define ECHO (tp->flags0&TECHO)
11: #define RAW (tp->flags0&TRAW)
12: #define CBREAK (tp->flags0&TCBREAK)
13: #define CRMOD (tp->flags0&TCRMOD)
14:
15: /*
16: * Keyboard-dependent things
17: */
18: #ifdef BLITKBD
19: #define BREAKKEY 0xE0
20: #define SCROLLKEY 0xB0 /* Why not NO SCRL? */
21: #undef ringbell
22: #define ringbell() DUART->b_data=0x02
23: #else
24: #define BREAKKEY 0x80
25: #define SCROLLKEY 0xB2 /* Why not NUM LOCK? */
26: #endif
27:
28: #define CTRLW 0x17
29: #define NSCRL 2
30: int HIWATER; /* #chars max to save off top of screen */
31: int LOWATER;
32: int doubleclickOK;
33:
34: typedef struct Type{
35: Frame *frame; /* Frame being typed at */
36: short start; /* start pos. of text to be sent to host */
37: short nchars; /* number of chars typed */
38: String old; /* old text scrolled off top */
39: char scroll;
40: }Type;
41:
42: String buf;
43: short scrltimeout;
44: #define M 3 /* margin around frame */
45:
46: windowproc(){
47: register Frame *f;
48: register got;
49: String rcvstr;
50: static String zerostr;
51: Type current;
52: if((current.frame=f=fralloc(P->layer->rect, M))==0){
53: mesg("can't allocate frame");
54: for(;;)
55: sleep(1000);
56: }
57: frinit(f);
58: setborder(P); /* frames always draw them black */
59: muxmesg((int)(P-proctab), C_POPLD);
60: current.start=0;
61: current.nchars=0;
62: current.scroll=0;
63: current.old=zerostr;
64: insure(¤t.old, 128, P);
65: rcvstr=zerostr;
66: insure(&rcvstr, 128, P);
67: Urequest(RCV|KBD|MOUSE);
68: Ucursswitch((Texture *)0);
69: setscroll(¤t);
70: for(;;){
71: linecurse(f); /* cursor is off, so turn it on */
72: do{
73: if(P->state&RESHAPED){
74: frsetrects(f, P->layer->rect);
75: drawframe(f); /* sets complete */
76: setborder(P);
77: if(!complete && current.scroll)
78: advance(¤t);
79: P->state&=~(RESHAPED|MOVED|BLOCKED);
80: linecurse(f); /* put it back */
81: }
82: }while((got=Uwait((P->state&BLOCKED)?
83: KBD|MOUSE|ALARM : KBD|MOUSE|RCV|ALARM))==MOUSE
84: && button123()==0);
85: linecurse(f); /* turn it off */
86: if(got&ALARM){
87: setscroll(¤t);
88: P->state&=~ALARMREQD;
89: }
90: if(got&MOUSE && button123())
91: wbuttons(¤t);
92: else if(got&KBD)
93: kbd(¤t, Ukbdchar());
94: else if(got&RCV)
95: rcv(¤t, &rcvstr);
96: }
97: }
98: bufinit(){
99: strzero(&buf);
100: if(VALMAXADDR)
101: HIWATER=10000, LOWATER=8000;
102: else
103: HIWATER=2500, LOWATER=1500;
104: }
105: getmuxbuf(s)
106: register String *s;
107: {
108: insure(s, buf.n, P);
109: movstring(buf.n, buf.s, s->s);
110: s->n=buf.n;
111: }
112: setmuxbuf(s)
113: String *s;
114: {
115: snarf(s, 0, s->n);
116: }
117: rcv(t, rcvstr)
118: Type *t;
119: register String *rcvstr;
120: {
121: register char *p;
122: register Frame *f=t->frame;
123: register i, posn, c;
124: int compl;
125: struct ttychars *tp=&P->ttychars;
126: /* Read the string */
127: c=Urcvchar();
128: loop:
129: while(c=='\b'){
130: if(t->start > 0)
131: deltype(t, t->start-1, t->start);
132: c=Urcvchar();
133: }
134: p=rcvstr->s;
135: for(i=0; c!=-1; c=Urcvchar()){ /*aplterm1*/
136: c&=0x7F;
137: if(c == '\b') break;
138: if(c=='\7')
139: ringbell(); /* smashes keyclick? */
140: if(c && c!='\r' && c<P->defaultfont->n){
141: *p++=c;
142: if(++i==rcvstr->size)
143: break;
144: }
145: }
146: rcvstr->n=i;
147: posn=t->start;
148: if(f->s1<posn && posn<f->s2){
149: t->start=posn=f->s1; /* before selected text; avoids problems */
150: t->nchars=0;
151: }
152: /* Undraw selection if necessary */
153: if(posn<f->s2 && f->s2>f->s1)
154: selectf(f, F_XOR);
155: /* Find where it goes */
156: instext(f, rcvstr, posn);
157: compl=inscomplete;
158: /* Adjust the selection and typing location */
159: if(posn<f->s2 || (f->s1==f->s2 && posn==f->s2)){
160: f->s1+=i;
161: f->s2+=i;
162: }
163: t->start+=i;
164: if(posn+i<f->s2 && f->s2>f->s1)
165: selectf(f, F_XOR);
166: if(!compl){
167: if(t->scroll)
168: advance(t);
169: else
170: P->state|=BLOCKED; /* so cat hugefile is safe */
171: }
172: if(c=='\b')
173: goto loop;
174: alarm(scrltimeout);
175: }
176: linecurse(t)
177: register Frame *t;
178: {
179: Point p;
180: if(t && t->str.s && t->s1==t->s2){
181: p=ptofchar(t, t->s1);
182: Rectf(Rpt(p, Pt(p.x+1, p.y+newlnsz)), F_XOR);
183: }
184: }
185: mesg(s)
186: char *s;
187: {
188: string(&defont, s, P->layer, add(P->rect.origin, Pt(2, 2)), F_STORE);
189: }
190: kbd(t, ac)
191: register Type *t;
192: char ac;
193: {
194: static int raw, echo, cbreak, crmod; /* can be static; we don't sleep here */
195: register Frame *f=t->frame;
196: register struct ttychars *tp=&P->ttychars;
197: int tounix;
198: unsigned char c;
199: c=ac;
200: if(c==SCROLLKEY){
201: scrlf(t, charofpt(f,
202: Pt(f->rect.origin.x, f->rect.origin.y+newlnsz*f->nlines/2)));
203: return;
204: }
205: if(f->s2>f->s1)
206: cut(t, 1);
207: if(f->s2>=t->start){
208: tounix=TRUE;
209: raw=RAW;
210: cbreak=CBREAK;
211: crmod=CRMOD;
212: echo=ECHO;
213: }else{
214: tounix=FALSE;
215: raw=FALSE;
216: cbreak=FALSE;
217: crmod=TRUE;
218: echo=TRUE;
219: }
220: if(raw && c!=BREAKKEY){ /* break goes, even in raw mode */
221: /* flush input */
222: t->start+=t->nchars;
223: t->nchars=0;
224: Noecho:
225: Usendchar(c);
226: return; /* no echo in raw mode */
227: }
228: if(c==BREAKKEY)
229: c=tp->intrc;
230: if(c==tp->intrc || c==tp->quitc){ /* always kill */
231: /* flush input */
232: t->start=f->str.n;
233: t->nchars=0;
234: muxkill(c==tp->intrc? 2 : 3, P);
235: return;
236: }
237: /* never raw mode */
238: if(!echo && t->nchars>0){ /* send off what's already there */
239: sendsubstr(f->str.s, t->start, t->nchars-t->start);
240: t->nchars=0;
241: t->start=f->str.n;
242: }
243: c&=0x7F; /* strip off sign bit from keypad */ /*aplterm2*/
244: if(c==tp->eofc && !cbreak){
245: if(tounix)
246: goto Send; /* throw away eofc */
247: return;
248: }
249: if(c=='\r' && crmod)
250: c='\n';
251: if(!echo)
252: goto Noecho;
253: if(f->s2>0 && f->str.s[f->s2-1]=='\\' &&
254: (c==tp->erase || (c==tp->kill&&tounix) || c==CTRLW ||
255: c==tp->stopc || c==tp->startc)){
256: deltype(t, f->s2-1, f->s2); /* throw away \ */
257: goto Ordinary;
258: }
259: if(c==tp->erase || c==CTRLW){
260: if(f->s1 > (tounix? t->start : 0))
261: deltype(t, f->s1-nback(f, c, tounix? t->start : 0), f->s1);
262: return;
263: }
264: if(c==tp->kill && tounix){
265: f->s2=f->str.n;
266: inschar(t, '@');
267: inschar(t, '\n');
268: t->start=f->s2;
269: t->nchars=0;
270: return;
271: }
272: if(c==tp->stopc){
273: P->state|=BLOCKED;
274: return;
275: }
276: if(c==tp->startc){
277: P->state&=~BLOCKED;
278: return;
279: }
280: Ordinary:
281: inschar(t, c);
282: if(tounix && (P->state&BLOCKED))
283: P->state&=~BLOCKED;
284: if(tounix && f->s2>t->start && (c=='\n' || (cbreak && c=='\r'))){
285: Send:
286: sendsubstr(f->str.s, t->start, f->s2);
287: t->nchars-=f->s2-t->start;
288: t->start+=f->s2-t->start;
289: }
290: }
291: nback(f, c, lim)
292: Frame *f;
293: {
294: register n=0, s1=f->s1;
295: register char *s=f->str.s+s1;
296: static char alphanl[]=
297: "\n0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
298: #define alphanum alphanl+1
299: if(s1 <= 0)
300: return 0;
301: if(c!=CTRLW || *--s=='\n')
302: return 1;
303: /* else it's ^W. first, get to an alphanumeric (or newline) */
304: while(n<s1-lim && notin(*s, alphanl))
305: --s, ++n;
306: /* *s is alphanumeric or space; now back up to non-alphanumeric */
307: while(n<s1 && !notin(*s, alphanum))
308: --s, ++n;
309: return n;
310: }
311: notin(c, s)
312: register c;
313: register char *s;
314: {
315: c&=0xFF;
316: while(*s)
317: if(c == *s++)
318: return FALSE;
319: return TRUE;
320: }
321: inschar(t, ac)
322: register Type *t;
323: {
324: static char c;
325: static String kbdstr={
326: &c,
327: 1,
328: 1
329: };
330: register Frame *f=t->frame;
331: c=ac;
332: instype(t, &kbdstr, f->s2);
333: if(!inscomplete)
334: scrlf(t, getto(f, f->s2));
335: setsel(f, f->s2+1);
336: }
337: getto(f, end)
338: register Frame *f;
339: {
340: register nl, nc, i;
341: nl=max(NSCRL, f->nlines/5);
342: nc=charofpt(f, f->rect.corner);
343: while(nc<end)
344: if(f->str.s[nc++]=='\n')
345: nl++;
346: /* nl is now #lines; find how many chars from start of frame */
347: for(i=nc=0; i<end; )
348: if(f->str.s[i++]=='\n'){
349: nc=i;
350: if(--nl<=0)
351: return nc;
352: }
353: return end;
354: }
355: advance(t)
356: Type *t;
357: {
358: /* should work first time unless lines are folded */
359: do; while(!scrlf(t, getto(t->frame, t->frame->str.n)));
360: }
361: insertstring(p, i, s, n) /* warning: must call insure() before this! */
362: String *p;
363: char *s;
364: {
365: String str;
366: str.s=s, str.n=n;
367: insstring(p, i, &str);
368: }
369: inserttype(t, s, n) /* warning: must call insure() before this! */
370: Type *t;
371: char *s;
372: {
373: register Frame *f=t->frame;
374: String str;
375: str.s=s, str.n=n;
376: selectf(f, F_XOR);
377: instext(f, &str, 0);
378: f->s1+=n;
379: f->s2+=n;
380: t->start+=n;
381: selectf(f, F_XOR);
382: }
383: scrlf(t, n)
384: register Type *t;
385: register n;
386: {
387: register Frame *f=t->frame;
388: if(n>0){
389: if(n>f->str.n)
390: n=f->str.n;
391: sendoldtext(t, n);
392: /* quick hack; don't worry about order of allocation */
393: insure(&t->old, t->old.n+n, P);
394: insertstring(&t->old, t->old.n, f->str.s, n);
395: if(t->old.n>HIWATER)
396: delstring(&t->old, 0, t->old.n-LOWATER);
397: if(n=deltype(t, 0, n)) /* all text in frame now visible */
398: P->state&=~BLOCKED;
399: }
400: setscroll(t);
401: return n;
402: }
403: scrlb(t, n)
404: register Type *t;
405: register n;
406: {
407: register Frame *f=t->frame;
408: register i;
409: if(n>0){
410: if(n>t->old.n)
411: n=t->old.n;
412: i=t->old.n-n;
413: while(i>0 && t->old.s[i-1]!='\n')
414: i--, n++;
415: insure(&t->old, t->old.n+n, P);
416: inserttype(t, t->old.s+i, n);
417: delstring(&t->old, i, t->old.n);
418: }
419: setscroll(t);
420: }
421: deltype(t, s1, s2)
422: register Type *t;
423: register s1, s2;
424: {
425: register Frame *f=t->frame;
426: int compl;
427: if(s2<=t->start)
428: t->start-=s2-s1;
429: else if(s1>=t->start)
430: t->nchars-=s2-s1;
431: else if(s2>t->start){ /* deletion overlaps start */
432: t->nchars-=s2-t->start;
433: t->start=s1;
434: }
435: selectf(f, F_XOR);
436: deltext(f, s1, s2);
437: compl=complete;
438: f->s1-=max(0, min(f->s1, s2)-s1);
439: f->s2-=max(0, min(f->s2, s2)-s1);
440: selectf(f, F_XOR);
441: return compl;
442: }
443: instype(t, s, s1)
444: register Type *t;
445: String *s;
446: register s1;
447: {
448: if(s->n>0){
449: if(s1<t->start)
450: t->start+=s->n;
451: else if(s1>=t->start)
452: t->nchars+=s->n;
453: instext(t->frame, s, s1);
454: }
455: }
456:
457: #define CUT 0
458: #define PASTE 1
459: #define SNARF 2
460: #define SENDIT 3
461: #define SCROLL 4
462:
463: #define UP 0
464: #define DOWN 1
465:
466: static char *editstrs[]={
467: "cut",
468: "paste",
469: "snarf",
470: "send",
471: 0,
472: 0,
473: };
474: static Menu editmenu={editstrs};
475:
476: wbuttons(t)
477: register Type *t;
478: {
479: register Frame *f=t->frame;
480: static char *scrollstrs[]={ "scroll", "noscroll" };
481: if(!ptinrect(mouse.xy, f->totalrect)){ /* not for us anyway */
482: doubleclickOK=0;
483: return;
484: }
485: if(ptinrect(mouse.xy, f->scrollrect))
486: scroll(t, mouse.buttons);
487: else if(button1()){
488: if(ptinrect(mouse.xy, f->rect))
489: frselect(f, mouse.xy);
490: }else if(button2()){
491: doubleclickOK=0;
492: editstrs[SCROLL]=scrollstrs[t->scroll];
493: switch(menuhit(&editmenu, 2)){
494: case CUT:
495: cut(t, 1);
496: break;
497: case PASTE:
498: paste(t, &buf);
499: break;
500: case SNARF:
501: if(f->s2>f->s1)
502: snarf(&f->str, f->s1, f->s2);
503: break;
504: case SENDIT:
505: send(t);
506: break;
507: case SCROLL:
508: if((t->scroll^=1) &&
509: (frameop(f, opnull, f->rect.origin,
510: f->str.s, f->str.n), !complete))
511: advance(t);
512: break;
513: }
514: }else{
515: doubleclickOK=0;
516: Urequest(RCV|KBD);
517: sleep(2);
518: Urequest(RCV|KBD|MOUSE);
519: }
520: }
521: snarf(p, i, j)
522: register String *p;
523: register short i, j;
524: {
525: register n = j-i;
526: insure(&buf, n, (struct Proc *)0);
527: movstring(n, p->s+i, buf.s);
528: buf.n = n;
529: }
530: cut(t, save)
531: register Type *t;
532: {
533: register n;
534: register Frame *f=t->frame;
535: if((n=f->s1) != f->s2){
536: if(save)
537: snarf(&f->str, n, f->s2);
538: deltype(t, f->s1, f->s2);
539: f->s1=f->s2;
540: setsel(f, n);
541: P->state&=~BLOCKED; /* in case we are suspended */
542: }
543: }
544: paste(t, s)
545: register Type *t;
546: String *s;
547: {
548: register Frame *f=t->frame;
549: if(s->n==0)
550: return;
551: cut(t, 0);
552: instype(t, s, f->s1);
553: f->s2=f->s1+s->n;
554: selectf(f, F_XOR);
555: }
556: send(t)
557: register Type *t;
558: {
559: register Frame *f=t->frame;
560: if(f->s1!=f->s2)
561: snarf(&f->str, f->s1, f->s2);
562: if(buf.n==0)
563: return;
564: if(t->nchars)
565: deltype(t, t->start, t->start+t->nchars);
566: if(P->ttychars.flags0&TECHO){
567: instext(f, &buf, f->str.n);
568: if(!inscomplete)
569: advance(t);
570: }
571: selectf(f, F_XOR);
572: f->s1=f->s2=f->str.n;
573: sendsubstr(buf.s, 0, buf.n);
574: if(buf.s[buf.n-1]!='\n'){
575: sendnchars(1, "\n");
576: if((P->ttychars.flags0&(TRAW|TCBREAK|TECHO))==TECHO)
577: inschar(t, '\n');
578: delim();
579: }
580: /* else the delim's already been sent */
581: t->start=f->s2;
582: t->nchars=0;
583: }
584: sendsubstr(s, beg, end)
585: register char *s;
586: {
587: register m, n;
588: if(beg==end){
589: delim();
590: return;
591: }
592: for(m=beg; m<end; m=n+1){
593: /* invariant: n is the last character we are going to send */
594: for(n=m; n<end && s[n]!='\n'; n++)
595: if(n==end-1)
596: break;
597: sendnchars(n-m+1, s+m);
598: if(n<end && s[n]=='\n')
599: delim();
600: }
601: }
602: sendoldtext(t, n)
603: register Type *t;
604: {
605: if(t->start<n && t->nchars>0){
606: if(n>t->start+t->nchars)
607: n=t->start+t->nchars;
608: sendsubstr(t->frame->str.s, t->start, n);
609: }
610: }
611: Texture grey = {
612: 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA,
613: 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA,
614: };
615: Point
616: scrollclip(p)
617: Point p;
618: {
619: if(p.x<0){
620: p.y-=p.x;
621: p.x=0;
622: }
623: if(p.y>SCROLLRANGE)
624: p.y=SCROLLRANGE;
625: return p;
626: }
627: Rectangle
628: scrollmark(f, p)
629: register Frame *f;
630: Point p;
631: {
632: Rectangle r;
633: p=scrollclip(p);
634: r=f->scrollrect;
635: r.origin.y=clixtopix(f, p.x);
636: r.corner.y=clixtopix(f, p.y);
637: return r;
638: }
639: clixtopix(f, y)
640: register Frame *f;
641: {
642: return f->scrollrect.origin.y+muldiv(f->nlines*newlnsz, y, SCROLLRANGE);
643: }
644: pixtoclix(f, y)
645: register Frame *f;
646: {
647: return muldiv(y-f->rect.origin.y, SCROLLRANGE, f->nlines*newlnsz);
648: }
649: drawscrollbar(f)
650: register Frame *f;
651: {
652: Rectangle r;
653: register Bitmap *b; /* offscreen to avoid flicker */
654: r=inset(f->scrollrect, -1);
655: b=balloc(r);
656: if(b==0)
657: b=(Bitmap *)D;
658: Urectf(b, r, F_OR);
659: lrectf(b, scrollmark(f, f->scroll), F_XOR);
660: Ubitblt(b, r, D, r.origin, F_STORE);
661: if(b!=(Bitmap *)D)
662: bfree(b);
663: }
664: setscroll(t)
665: register Type *t;
666: {
667: register Frame *f=t->frame;
668: Point new;
669: register x, y;
670: x=f->rect.origin.y+1; /* a little margin at the top */
671: y=f->rect.corner.y-1; /* and bottom */
672: if(t->old.n+f->str.n>0)
673: x+=muldiv(f->nlines*newlnsz, t->old.n, t->old.n+f->str.n);
674: if(f->cpl[f->nlines-1]>0){
675: int n;
676: n=charofpt(f, Pt(XMAX, YMAX));
677: y-=muldiv(f->nlines*newlnsz, f->str.n-n, t->old.n+f->str.n);
678: }
679: if(x>y-(f->rect.corner.y-f->rect.origin.y)/30)
680: x=y-(f->rect.corner.y-f->rect.origin.y)/30;
681: if(y<x+(f->rect.corner.y-f->rect.origin.y)/30)
682: y=x+(f->rect.corner.y-f->rect.origin.y)/30;
683: new.x=pixtoclix(f, x);
684: new.y=pixtoclix(f, y);
685: if(abs(f->scroll.x-new.x)>20 || abs(f->scroll.y-new.y)>20){
686: f->scroll=new;
687: drawscrollbar(f);
688: }
689: }
690: Point
691: checkmouse(f, mousep, p)
692: Frame *f;
693: Point mousep, p;
694: {
695: if(!ptinrect(mousep, f->scrollrect)){
696: extern Rectangle Null;
697: return Null.origin;
698: }
699: return p;
700: }
701: Point
702: but1func(f, p)
703: register Frame *f;
704: Point p;
705: {
706: register delta=muldiv(p.y-f->rect.origin.y, f->scroll.y-f->scroll.x, f->nlines*newlnsz);
707: return checkmouse(f, p, sub(f->scroll, Pt(delta, delta)));
708: }
709: Point
710: but2func(f, p)
711: register Frame *f;
712: Point p;
713: {
714: Point scroll;
715: register size=(f->scroll.y-f->scroll.x)/2;
716: scroll.x=pixtoclix(f, p.y)-size;
717: scroll.y=pixtoclix(f, p.y)+size;
718: return checkmouse(f, p, scroll);
719: }
720: Point
721: but3func(f, p)
722: register Frame *f;
723: Point p;
724: {
725: register delta=muldiv(p.y-f->rect.origin.y, f->scroll.y-f->scroll.x, f->nlines*newlnsz);
726: return checkmouse(f, p, add(f->scroll, Pt(delta, delta)));
727: }
728: typedef Point (*ptrfpoint)();
729: ptrfpoint butfunc[]={
730: 0,
731: but1func,
732: but2func,
733: but3func,
734: };
735: Point
736: guide(m, p)
737: Point m, p;
738: {
739: if(abs(m.x-p.x)<3)
740: m.x=p.x;
741: return m;
742: }
743: scrollbar(f, but)
744: register Frame *f;
745: {
746: ptrfpoint fp;
747: Point pt;
748: fp=butfunc[but];
749: pt=mouse.xy;
750: while(button(but)){
751: ltexture(D, scrollmark(f, (*fp)(f, pt)), &grey, F_XOR);
752: do nap(3); while(eqpt(mouse.xy, pt) && button(but));
753: ltexture(D, scrollmark(f, (*fp)(f, pt)), &grey, F_XOR);
754: cursset(pt=guide(mouse.xy, pt));
755: }
756: if(ptinrect(pt, f->scrollrect)){
757: f->scroll=(*fp)(f, pt);
758: if(f->scroll.x<0){
759: f->scroll.y-=f->scroll.x;
760: f->scroll.x=0;
761: }
762: if(f->scroll.x>SCROLLRANGE){
763: f->scroll.y-=f->scroll.x-SCROLLRANGE;
764: f->scroll.x=SCROLLRANGE;
765: }
766: return 1;
767: }
768: return 0;
769: }
770: scroll(t, but)
771: register Type *t;
772: {
773: register Frame *f=t->frame;
774: Point old, new;
775: register y, b;
776: old=f->scroll;
777: if(scrollbar(f, b=whichbutton())){
778: new=f->scroll;
779: f->scroll=old; /* ugh */
780: y=mouse.xy.y;
781: if(b==2){
782: y=muldiv(f->str.n+t->old.n, new.x, SCROLLRANGE);
783: if(y>=t->old.n){
784: y-=t->old.n;
785: do; while(y<f->str.n && f->str.s[y++]!='\n');
786: scrlf(t, y);
787: }else
788: scrlb(t, t->old.n-y);
789: }else if(new.x>=old.x)
790: scrlf(t, charofpt(f, Pt(f->rect.origin.x, y)));
791: else
792: scrlb(t, oldlinepos(t, (y-f->scrollrect.origin.y)/newlnsz));
793: }
794: }
795: oldlinepos(t, n)
796: register Type *t;
797: register n;
798: {
799: register i=t->old.n;
800: while(n>0 && i>0)
801: if(t->old.s[--i]=='\n')
802: --n;
803: return t->old.n-i;
804: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.