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