blob: c332d7a81b2bd0081527e8275f892fb637d1720a [file] [log] [blame]
rsc84b1cb72003-09-30 17:47:44 +00001#include <u.h>
2#include <libc.h>
3#include <draw.h>
4#include <thread.h>
5#include <mouse.h>
6#include <cursor.h>
7#include <keyboard.h>
8#include <frame.h>
9#include <plumb.h>
10#include "flayer.h"
11#include "samterm.h"
12
13#define HSIZE 3 /* Type + short count */
14Header h;
15uchar indata[DATASIZE+1]; /* room for NUL */
16uchar outdata[DATASIZE];
17short outcount;
18int hversion;
rsc941c9f32003-10-11 02:45:02 +000019int hostfd[2];
rsc84b1cb72003-09-30 17:47:44 +000020
21void inmesg(Hmesg, int);
22int inshort(int);
23long inlong(int);
24long invlong(int);
25void hsetdot(int, long, long);
26void hmoveto(int, long);
27void hsetsnarf(int);
28/* void hplumb(int); */
29void clrlock(void);
30int snarfswap(char*, int, char**);
31
32void
33rcv(void)
34{
35 int c;
36 static int state = 0;
37 static int count = 0;
38 static int i = 0;
39 static int errs = 0;
40
41 while((c=rcvchar()) != -1)
42 switch(state){
43 case 0:
44 h.type = c;
45 state++;
46 break;
47
48 case 1:
49 h.count0 = c;
50 state++;
51 break;
52
53 case 2:
54 h.count1 = c;
55 count = h.count0|(h.count1<<8);
56 i = 0;
57 if(count > DATASIZE){
58 if(++errs < 5){
59 dumperrmsg(count, h.type, h.count0, c);
60 state = 0;
61 continue;
62 }
63 fprint(2, "type %d count %d\n", h.type, count);
64 panic("count>DATASIZE");
65 }
66 if(count == 0)
67 goto zerocount;
68 state++;
69 break;
70
71 case 3:
72 indata[i++] = c;
73 if(i == count){
74 zerocount:
75 indata[i] = 0;
76 inmesg(h.type, count);
77 state = count = 0;
78 continue;
79 }
80 break;
81 }
82}
83
84Text *
85whichtext(int tg)
86{
87 int i;
88
89 for(i=0; i<nname; i++)
90 if(tag[i] == tg)
91 return text[i];
92 panic("whichtext");
93 return 0;
94}
95
96void
97inmesg(Hmesg type, int count)
98{
99 Text *t;
100 int i, m;
101 long l;
102 Flayer *lp;
103
104 m = inshort(0);
105 l = inlong(2);
106 switch(type){
107 case -1:
108 panic("rcv error");
109 default:
110 fprint(2, "type %d\n", type);
111 panic("rcv unknown");
112
113 case Hversion:
114 hversion = m;
115 break;
116
117 case Hbindname:
118 l = invlong(2); /* for 64-bit pointers */
119 if((i=whichmenu(m)) < 0)
120 break;
121 /* in case of a race, a bindname may already have occurred */
122 if((t=whichtext(m)) == 0)
123 t=(Text *)l;
124 else /* let the old one win; clean up the new one */
125 while(((Text *)l)->nwin>0)
126 closeup(&((Text *)l)->l[((Text *)l)->front]);
127 text[i] = t;
128 text[i]->tag = m;
129 break;
130
131 case Hcurrent:
132 if(whichmenu(m)<0)
133 break;
134 t = whichtext(m);
135 i = which && ((Text *)which->user1)==&cmd && m!=cmd.tag;
136 if(t==0 && (t = sweeptext(0, m))==0)
137 break;
138 if(t->l[t->front].textfn==0)
139 panic("Hcurrent");
140 lp = &t->l[t->front];
141 if(i){
142 flupfront(lp);
143 flborder(lp, 0);
144 work = lp;
145 }else
146 current(lp);
147 break;
148
149 case Hmovname:
150 if((m=whichmenu(m)) < 0)
151 break;
152 t = text[m];
153 l = tag[m];
154 i = name[m][0];
155 text[m] = 0; /* suppress panic in menudel */
156 menudel(m);
157 if(t == &cmd)
158 m = 0;
159 else{
160 if (nname>0 && text[0]==&cmd)
161 m = 1;
162 else m = 0;
163 for(; m<nname; m++)
164 if(strcmp((char*)indata+2, (char*)name[m]+1)<0)
165 break;
166 }
167 menuins(m, indata+2, t, i, (int)l);
168 break;
169
170 case Hgrow:
171 if(whichmenu(m) >= 0)
172 hgrow(m, l, inlong(6), 1);
173 break;
174
175 case Hnewname:
176 menuins(0, (uchar *)"", (Text *)0, ' ', m);
177 break;
178
179 case Hcheck0:
180 i = whichmenu(m);
181 if(i>=0) {
182 t = text[i];
183 if(t)
184 t->lock++;
185 outTs(Tcheck, m);
186 }
187 break;
188
189 case Hcheck:
190 i = whichmenu(m);
191 if(i>=0) {
192 t = text[i];
193 if(t && t->lock)
194 t->lock--;
195 hcheck(m);
196 }
197 break;
198
199 case Hunlock:
200 clrlock();
201 break;
202
203 case Hdata:
204 if(whichmenu(m) >= 0)
205 l += hdata(m, l, indata+6, count-6);
206 Checkscroll:
207 if(m == cmd.tag){
208 for(i=0; i<NL; i++){
209 lp = &cmd.l[i];
210 if(lp->textfn)
211 center(lp, l>=0? l : lp->p1);
212 }
213 }
214 break;
215
216 case Horigin:
217 if(whichmenu(m) >= 0)
218 horigin(m, l);
219 break;
220
221 case Hunlockfile:
222 if(whichmenu(m)>=0 && (t = whichtext(m))->lock){
223 --t->lock;
224 l = -1;
225 goto Checkscroll;
226 }
227 break;
228
229 case Hsetdot:
230 if(whichmenu(m) >= 0)
231 hsetdot(m, l, inlong(6));
232 break;
233
234 case Hgrowdata:
235 if(whichmenu(m)<0)
236 break;
237 hgrow(m, l, inlong(6), 0);
238 whichtext(m)->lock++; /* fake the request */
239 l += hdata(m, l, indata+10, count-10);
240 goto Checkscroll;
241
242 case Hmoveto:
243 if(whichmenu(m)>=0)
244 hmoveto(m, l);
245 break;
246
247 case Hclean:
248 if((m = whichmenu(m)) >= 0)
249 name[m][0] = ' ';
250 break;
251
252 case Hdirty:
253 if((m = whichmenu(m))>=0)
254 name[m][0] = '\'';
255 break;
256
257 case Hdelname:
258 if((m=whichmenu(m)) >= 0)
259 menudel(m);
260 break;
261
262 case Hcut:
263 if(whichmenu(m) >= 0)
264 hcut(m, l, inlong(6));
265 break;
266
267 case Hclose:
268 if(whichmenu(m)<0 || (t = whichtext(m))==0)
269 break;
270 l = t->nwin;
271 for(i = 0,lp = t->l; l>0 && i<NL; i++,lp++)
272 if(lp->textfn){
273 closeup(lp);
274 --l;
275 }
276 break;
277
278 case Hsetpat:
279 setpat((char *)indata);
280 break;
281
282 case Hsetsnarf:
283 hsetsnarf(m);
284 break;
285
286 case Hsnarflen:
287 snarflen = inlong(0);
288 break;
289
290 case Hack:
291 outT0(Tack);
292 break;
293
294 case Hexit:
295 outT0(Texit);
296 threadexitsall(nil);
297 break;
298
299/*
300 case Hplumb:
301 hplumb(m);
302 break;
303*/
304 }
305}
306
307void
308setlock(void)
309{
310 hostlock++;
311 setcursor(mousectl, cursor = &lockarrow);
312}
313
314void
315clrlock(void)
316{
317 hasunlocked = 1;
318 if(hostlock > 0)
319 hostlock--;
320 if(hostlock == 0)
321 setcursor(mousectl, cursor=(Cursor *)0);
322}
323
324void
325startfile(Text *t)
326{
327 outTsv(Tstartfile, t->tag, t); /* for 64-bit pointers */
328 setlock();
329}
330
331void
332startnewfile(int type, Text *t)
333{
334 t->tag = Untagged;
335 outTv(type, t); /* for 64-bit pointers */
336}
337
338int
339inshort(int n)
340{
341 return indata[n]|(indata[n+1]<<8);
342}
343
344long
345inlong(int n)
346{
347 return indata[n]|(indata[n+1]<<8)|
348 ((long)indata[n+2]<<16)|((long)indata[n+3]<<24);
349}
350
351long
352invlong(int n)
353{
354 long l;
355
356 l = (indata[n+7]<<24) | (indata[n+6]<<16) | (indata[n+5]<<8) | indata[n+4];
357 l = (l<<16) | (indata[n+3]<<8) | indata[n+2];
358 l = (l<<16) | (indata[n+1]<<8) | indata[n];
359 return l;
360}
361
362void
363outT0(Tmesg type)
364{
365 outstart(type);
366 outsend();
367}
368
369void
370outTl(Tmesg type, long l)
371{
372 outstart(type);
373 outlong(l);
374 outsend();
375}
376
377void
378outTs(Tmesg type, int s)
379{
380 outstart(type);
381 outshort(s);
382 outsend();
383}
384
385void
386outTss(Tmesg type, int s1, int s2)
387{
388 outstart(type);
389 outshort(s1);
390 outshort(s2);
391 outsend();
392}
393
394void
395outTsll(Tmesg type, int s1, long l1, long l2)
396{
397 outstart(type);
398 outshort(s1);
399 outlong(l1);
400 outlong(l2);
401 outsend();
402}
403
404void
405outTsl(Tmesg type, int s1, long l1)
406{
407 outstart(type);
408 outshort(s1);
409 outlong(l1);
410 outsend();
411}
412
413void
414outTsv(Tmesg type, int s1, void *l1)
415{
416 outstart(type);
417 outshort(s1);
418 outvlong(l1);
419 outsend();
420}
421
422void
423outTv(Tmesg type, void *l1)
424{
425 outstart(type);
426 outvlong(l1);
427 outsend();
428}
429
430void
431outTslS(Tmesg type, int s1, long l1, Rune *s)
432{
433 char buf[DATASIZE*3+1];
434 char *c;
435
436 outstart(type);
437 outshort(s1);
438 outlong(l1);
439 c = buf;
440 while(*s)
441 c += runetochar(c, s++);
442 *c++ = 0;
443 outcopy(c-buf, (uchar *)buf);
444 outsend();
445}
446
447void
448outTsls(Tmesg type, int s1, long l1, int s2)
449{
450 outstart(type);
451 outshort(s1);
452 outlong(l1);
453 outshort(s2);
454 outsend();
455}
456
457void
458outstart(Tmesg type)
459{
460 outdata[0] = type;
461 outcount = 0;
462}
463
464void
465outcopy(int count, uchar *data)
466{
467 while(count--)
468 outdata[HSIZE+outcount++] = *data++;
469}
470
471void
472outshort(int s)
473{
474 uchar buf[2];
475
476 buf[0]=s;
477 buf[1]=s>>8;
478 outcopy(2, buf);
479}
480
481void
482outlong(long l)
483{
484 uchar buf[4];
485
486 buf[0]=l;
487 buf[1]=l>>8;
488 buf[2]=l>>16;
489 buf[3]=l>>24;
490 outcopy(4, buf);
491}
492
493void
494outvlong(void *v)
495{
496 int i;
497 ulong l;
498 uchar buf[8];
499
500 l = (ulong) v;
501 for(i = 0; i < sizeof(buf); i++, l >>= 8)
502 buf[i] = l;
503
504 outcopy(8, buf);
505}
506
507void
508outsend(void)
509{
510 if(outcount>DATASIZE-HSIZE)
511 panic("outcount>sizeof outdata");
512 outdata[1]=outcount;
513 outdata[2]=outcount>>8;
rsc941c9f32003-10-11 02:45:02 +0000514 if(write(hostfd[1], (char *)outdata, outcount+HSIZE)!=outcount+HSIZE)
rsc84b1cb72003-09-30 17:47:44 +0000515 panic("write error");
516}
517
518
519void
520hsetdot(int m, long p0, long p1)
521{
522 Text *t = whichtext(m);
523 Flayer *l = &t->l[t->front];
524
525 flushtyping(1);
526 flsetselect(l, p0, p1);
527}
528
529void
530horigin(int m, long p0)
531{
532 Text *t = whichtext(m);
533 Flayer *l = &t->l[t->front];
534 long a;
535 ulong n;
536 Rune *r;
537
538 if(!flprepare(l)){
539 l->origin = p0;
540 return;
541 }
542 a = p0-l->origin;
543 if(a>=0 && a<l->f.nchars)
544 frdelete(&l->f, 0, a);
545 else if(a<0 && -a<l->f.nchars){
546 r = rload(&t->rasp, p0, l->origin, &n);
547 frinsert(&l->f, r, r+n, 0);
548 }else
549 frdelete(&l->f, 0, l->f.nchars);
550 l->origin = p0;
551 scrdraw(l, t->rasp.nrunes);
552 if(l->visible==Some)
553 flrefresh(l, l->entire, 0);
554 hcheck(m);
555}
556
557void
558hmoveto(int m, long p0)
559{
560 Text *t = whichtext(m);
561 Flayer *l = &t->l[t->front];
562
563 if(p0<l->origin || p0-l->origin>l->f.nchars*9/10)
564 outTsll(Torigin, m, p0, 2L);
565}
566
567void
568hcheck(int m)
569{
570 Flayer *l;
571 Text *t;
572 int reqd = 0, i;
573 long n, nl, a;
574 Rune *r;
575
576 if(m == Untagged)
577 return;
578 t = whichtext(m);
579 if(t == 0) /* possible in a half-built window */
580 return;
581 for(l = &t->l[0], i = 0; i<NL; i++, l++){
582 if(l->textfn==0 || !flprepare(l)) /* BUG: don't
583 need this if BUG below
584 is fixed */
585 continue;
586 a = t->l[i].origin;
587 n = rcontig(&t->rasp, a, a+l->f.nchars, 1);
588 if(n<l->f.nchars) /* text missing in middle of screen */
589 a+=n;
590 else{ /* text missing at end of screen? */
591 Again:
592 if(l->f.lastlinefull)
593 goto Checksel; /* all's well */
594 a = t->l[i].origin+l->f.nchars;
595 n = t->rasp.nrunes-a;
596 if(n==0)
597 goto Checksel;
598 if(n>TBLOCKSIZE)
599 n = TBLOCKSIZE;
600 n = rcontig(&t->rasp, a, a+n, 1);
601 if(n>0){
602 rload(&t->rasp, a, a+n, 0);
603 nl = l->f.nchars;
604 r = scratch;
605 flinsert(l, r, r+n, l->origin+nl);
606 if(nl == l->f.nchars) /* made no progress */
607 goto Checksel;
608 goto Again;
609 }
610 }
611 if(!reqd){
612 n = rcontig(&t->rasp, a, a+TBLOCKSIZE, 0);
613 if(n <= 0)
614 panic("hcheck request==0");
615 outTsls(Trequest, m, a, (int)n);
616 outTs(Tcheck, m);
617 t->lock++; /* for the Trequest */
618 t->lock++; /* for the Tcheck */
619 reqd++;
620 }
621 Checksel:
622 flsetselect(l, l->p0, l->p1);
623 }
624}
625
626void
627flnewlyvisible(Flayer *l)
628{
629 hcheck(((Text *)l->user1)->tag);
630}
631
632void
633hsetsnarf(int nc)
634{
635 char *s2;
636 char *s1;
637 int i;
638 int n;
639
640 setcursor(mousectl, &deadmouse);
641 s2 = alloc(nc+1);
642 for(i=0; i<nc; i++)
643 s2[i] = getch();
644 s2[nc] = 0;
645 n = snarfswap(s2, nc, &s1);
646 if(n >= 0){
647 if(!s1)
648 n = 0;
649 s1 = realloc(s1, n+1);
650 if (!s1)
651 panic("realloc");
652 s1[n] = 0;
653 snarflen = n;
654 outTs(Tsetsnarf, n);
rsc941c9f32003-10-11 02:45:02 +0000655 if(n>0 && write(hostfd[1], s1, n)!=n)
rsc84b1cb72003-09-30 17:47:44 +0000656 panic("snarf write error");
657 free(s1);
658 }else
659 outTs(Tsetsnarf, 0);
660 free(s2);
661 setcursor(mousectl, cursor);
662}
663
664/*
665void
666hplumb(int nc)
667{
668 int i;
669 char *s;
670 Plumbmsg *m;
671
672 s = alloc(nc);
673 for(i=0; i<nc; i++)
674 s[i] = getch();
675 if(plumbfd > 0){
676 m = plumbunpack(s, nc);
677 if(m != 0)
678 plumbsend(plumbfd, m);
679 plumbfree(m);
680 }
681 free(s);
682}
683*/
684
685void
686hgrow(int m, long a, long new, int req)
687{
688 int i;
689 Flayer *l;
690 Text *t = whichtext(m);
691 long o, b;
692
693 if(new <= 0)
694 panic("hgrow");
695 rresize(&t->rasp, a, 0L, new);
696 for(l = &t->l[0], i = 0; i<NL; i++, l++){
697 if(l->textfn == 0)
698 continue;
699 o = l->origin;
700 b = a-o-rmissing(&t->rasp, o, a);
701 if(a < o)
702 l->origin+=new;
703 if(a < l->p0)
704 l->p0+=new;
705 if(a < l->p1)
706 l->p1+=new;
707 /* must prevent b temporarily becoming unsigned */
708 if(!req || a<o || (b>0 && b>l->f.nchars) ||
709 (l->f.nchars==0 && a-o>0))
710 continue;
711 if(new>TBLOCKSIZE)
712 new = TBLOCKSIZE;
713 outTsls(Trequest, m, a, (int)new);
714 t->lock++;
715 req = 0;
716 }
717}
718
719int
720hdata1(Text *t, long a, Rune *r, int len)
721{
722 int i;
723 Flayer *l;
724 long o, b;
725
726 for(l = &t->l[0], i=0; i<NL; i++, l++){
727 if(l->textfn==0)
728 continue;
729 o = l->origin;
730 b = a-o-rmissing(&t->rasp, o, a);
731 /* must prevent b temporarily becoming unsigned */
732 if(a<o || (b>0 && b>l->f.nchars))
733 continue;
734 flinsert(l, r, r+len, o+b);
735 }
736 rdata(&t->rasp, a, a+len, r);
737 rclean(&t->rasp);
738 return len;
739}
740
741int
742hdata(int m, long a, uchar *s, int len)
743{
744 int i, w;
745 Text *t = whichtext(m);
746 Rune buf[DATASIZE], *r;
747
748 if(t->lock)
749 --t->lock;
750 if(len == 0)
751 return 0;
752 r = buf;
753 for(i=0; i<len; i+=w,s+=w)
754 w = chartorune(r++, (char*)s);
755 return hdata1(t, a, buf, r-buf);
756}
757
758int
759hdatarune(int m, long a, Rune *r, int len)
760{
761 Text *t = whichtext(m);
762
763 if(t->lock)
764 --t->lock;
765 if(len == 0)
766 return 0;
767 return hdata1(t, a, r, len);
768}
769
770void
771hcut(int m, long a, long old)
772{
773 Flayer *l;
774 Text *t = whichtext(m);
775 int i;
776 long o, b;
777
778 if(t->lock)
779 --t->lock;
780 for(l = &t->l[0], i = 0; i<NL; i++, l++){
781 if(l->textfn == 0)
782 continue;
783 o = l->origin;
784 b = a-o-rmissing(&t->rasp, o, a);
785 /* must prevent b temporarily becoming unsigned */
786 if((b<0 || b<l->f.nchars) && a+old>=o){
787 fldelete(l, b<0? o : o+b,
788 a+old-rmissing(&t->rasp, o, a+old));
789 }
790 if(a+old<o)
791 l->origin-=old;
792 else if(a<=o)
793 l->origin = a;
794 if(a+old<l->p0)
795 l->p0-=old;
796 else if(a<=l->p0)
797 l->p0 = a;
798 if(a+old<l->p1)
799 l->p1-=old;
800 else if(a<=l->p1)
801 l->p1 = a;
802 }
803 rresize(&t->rasp, a, old, 0L);
804 rclean(&t->rasp);
805}