master
rows.c
ohmu
·
2026-09-13
1#include <u.h>
2#include <libc.h>
3#include <draw.h>
4#include <thread.h>
5#include <cursor.h>
6#include <mouse.h>
7#include <keyboard.h>
8#include <frame.h>
9#include <fcall.h>
10#include <bio.h>
11#include <plumb.h>
12#include <libsec.h>
13#include "parser.h"
14#include "dat.h"
15#include "fns.h"
16
17static Rune Lcolhdr[] = {
18 'N', 'e', 'w', 'c', 'o', 'l', ' ',
19 'K', 'i', 'l', 'l', ' ',
20 'P', 'u', 't', 'a', 'l', 'l', ' ',
21 'D', 'u', 'm', 'p', ' ',
22 'E', 'x', 'i', 't', ' ',
23 0
24};
25
26Image *rowsbg;
27Image *bordercol;
28
29void
30rowinit(Row *row, Rectangle r)
31{
32 Rectangle r1;
33 Text *t;
34
35 if(ispastel("root"))
36 rowsbg = allocimagemix(display, C_ROOTBG, C_MIX);
37 else
38 rowsbg = allocimage(display, Rect(0,0,1,1), RGBA32, 1, C_ROOTBG);
39
40 if(ispastel("border"))
41 bordercol = allocimagemix(display, C_BORDER, C_MIX);
42 else
43 bordercol = allocimage(display, Rect(0,0,1,1), RGBA32, 1, C_BORDER);
44
45 draw(screen, r, rowsbg, nil, ZP);
46 row->r = r;
47 row->col = nil;
48 row->ncol = 0;
49 r1 = r;
50 r1.max.y = r1.min.y + font->height;
51 t = &row->tag;
52 textinit(t, fileaddtext(nil, t), r1, rfget(FALSE, FALSE, FALSE, nil), tagcols);
53 t->what = Rowtag;
54 t->row = row;
55 t->w = nil;
56 t->col = nil;
57 r1.min.y = r1.max.y;
58 r1.max.y += Border;
59 draw(screen, r1, bordercol, nil, ZP);
60 textinsert(t, 0, Lcolhdr, 29, TRUE);
61 textsetselect(t, t->file->b.nc, t->file->b.nc);
62}
63
64Column*
65rowadd(Row *row, Column *c, int x)
66{
67 Rectangle r, r1;
68 Column *d;
69 int i;
70
71 d = nil;
72 r = row->r;
73 r.min.y = row->tag.fr.r.max.y+Border;
74 if(x<r.min.x && row->ncol>0){ /*steal 40% of last column by default */
75 d = row->col[row->ncol-1];
76 x = d->r.min.x + 3*Dx(d->r)/5;
77 }
78 /* look for column we'll land on */
79 for(i=0; i<row->ncol; i++){
80 d = row->col[i];
81 if(x < d->r.max.x)
82 break;
83 }
84 if(row->ncol > 0){
85 if(i < row->ncol)
86 i++; /* new column will go after d */
87 r = d->r;
88 if(Dx(r) < 100)
89 return nil;
90 draw(screen, r, rowsbg, nil, ZP);
91 r1 = r;
92 r1.max.x = min(x-Border, r.max.x-50);
93 if(Dx(r1) < 50)
94 r1.max.x = r1.min.x+50;
95 colresize(d, r1);
96 r1.min.x = r1.max.x;
97 r1.max.x = r1.min.x+Border;
98 draw(screen, r1, bordercol, nil, ZP);
99 r.min.x = r1.max.x;
100 }
101 if(c == nil){
102 c = emalloc(sizeof(Column));
103 colinit(c, r);
104 incref(&reffont.ref);
105 }else
106 colresize(c, r);
107 c->row = row;
108 c->tag.row = row;
109 row->col = realloc(row->col, (row->ncol+1)*sizeof(Column*));
110 memmove(row->col+i+1, row->col+i, (row->ncol-i)*sizeof(Column*));
111 row->col[i] = c;
112 row->ncol++;
113 clearmouse();
114 return c;
115}
116
117void
118rowresize(Row *row, Rectangle r)
119{
120 int i, deltax;
121 Rectangle or, r1, r2;
122 Column *c;
123
124 or = row->r;
125 deltax = r.min.x - or.min.x;
126 row->r = r;
127 r1 = r;
128 r1.max.y = r1.min.y + font->height;
129 textresize(&row->tag, r1, TRUE);
130 r1.min.y = r1.max.y;
131 r1.max.y += Border;
132 draw(screen, r1, bordercol, nil, ZP);
133 r.min.y = r1.max.y;
134 r1 = r;
135 r1.max.x = r1.min.x;
136 for(i=0; i<row->ncol; i++){
137 c = row->col[i];
138 r1.min.x = r1.max.x;
139 /* the test should not be necessary, but guarantee we don't lose a pixel */
140 if(i == row->ncol-1)
141 r1.max.x = r.max.x;
142 else
143 r1.max.x = (c->r.max.x-or.min.x)*Dx(r)/Dx(or) + deltax;
144 if(i > 0){
145 r2 = r1;
146 r2.max.x = r2.min.x+Border;
147 draw(screen, r2, bordercol, nil, ZP);
148 r1.min.x = r2.max.x;
149 }
150 colresize(c, r1);
151 }
152}
153
154void
155rowdragcol(Row *row, Column *c, int _0)
156{
157 Rectangle r;
158 int i, b, x;
159 Point p, op;
160 Column *d;
161
162 USED(_0);
163
164 clearmouse();
165 setcursor(mousectl, &boxcursor);
166 b = mouse->buttons;
167 op = mouse->xy;
168 while(mouse->buttons == b)
169 readmouse(mousectl);
170 setcursor(mousectl, nil);
171 if(mouse->buttons){
172 while(mouse->buttons)
173 readmouse(mousectl);
174 return;
175 }
176
177 for(i=0; i<row->ncol; i++)
178 if(row->col[i] == c)
179 goto Found;
180 error("can't find column");
181
182 Found:
183 p = mouse->xy;
184 if((abs(p.x-op.x)<5 && abs(p.y-op.y)<5))
185 return;
186 if((i>0 && p.x<row->col[i-1]->r.min.x) || (i<row->ncol-1 && p.x>c->r.max.x)){
187 /* shuffle */
188 x = c->r.min.x;
189 rowclose(row, c, FALSE);
190 if(rowadd(row, c, p.x) == nil) /* whoops! */
191 if(rowadd(row, c, x) == nil) /* WHOOPS! */
192 if(rowadd(row, c, -1)==nil){ /* shit! */
193 rowclose(row, c, TRUE);
194 return;
195 }
196 colmousebut(c);
197 return;
198 }
199 if(i == 0)
200 return;
201 d = row->col[i-1];
202 if(p.x < d->r.min.x+80+Scrollwid)
203 p.x = d->r.min.x+80+Scrollwid;
204 if(p.x > c->r.max.x-80-Scrollwid)
205 p.x = c->r.max.x-80-Scrollwid;
206 r = d->r;
207 r.max.x = c->r.max.x;
208 draw(screen, r, bordercol, nil, ZP);
209 r.max.x = p.x;
210 colresize(d, r);
211 r = c->r;
212 r.min.x = p.x;
213 r.max.x = r.min.x;
214 r.max.x += Border;
215 draw(screen, r, bordercol, nil, ZP);
216 r.min.x = r.max.x;
217 r.max.x = c->r.max.x;
218 colresize(c, r);
219 colmousebut(c);
220}
221
222void
223rowclose(Row *row, Column *c, int dofree)
224{
225 Rectangle r;
226 int i;
227
228 for(i=0; i<row->ncol; i++)
229 if(row->col[i] == c)
230 goto Found;
231 error("can't find column");
232 Found:
233 r = c->r;
234 if(dofree)
235 colcloseall(c);
236 row->ncol--;
237 memmove(row->col+i, row->col+i+1, (row->ncol-i)*sizeof(Column*));
238 row->col = realloc(row->col, row->ncol*sizeof(Column*));
239 if(row->ncol == 0){
240 draw(screen, r, rowsbg, nil, ZP);
241 return;
242 }
243 if(i == row->ncol){ /* extend last column right */
244 c = row->col[i-1];
245 r.min.x = c->r.min.x;
246 r.max.x = row->r.max.x;
247 }else{ /* extend next window left */
248 c = row->col[i];
249 r.max.x = c->r.max.x;
250 }
251 draw(screen, r, rowsbg, nil, ZP);
252 colresize(c, r);
253}
254
255Column*
256rowwhichcol(Row *row, Point p)
257{
258 int i;
259 Column *c;
260
261 for(i=0; i<row->ncol; i++){
262 c = row->col[i];
263 if(ptinrect(p, c->r))
264 return c;
265 }
266 return nil;
267}
268
269Text*
270rowwhich(Row *row, Point p)
271{
272 Column *c;
273
274 if(ptinrect(p, row->tag.all))
275 return &row->tag;
276 c = rowwhichcol(row, p);
277 if(c)
278 return colwhich(c, p);
279 return nil;
280}
281
282Text*
283rowtype(Row *row, Rune r, Point p)
284{
285 Window *w;
286 Text *t;
287
288 if(r == 0)
289 r = Runeerror;
290
291 clearmouse();
292 qlock(&row->lk);
293 if(bartflag)
294 t = barttext;
295 else
296 t = rowwhich(row, p);
297 if(t!=nil && !(t->what==Tag && ptinrect(p, t->scrollr))){
298 w = t->w;
299 if(w == nil)
300 texttype(t, r);
301 else{
302 winlock(w, 'K');
303 wintype(w, t, r);
304 /* Expand tag if necessary */
305 if(t->what == Tag){
306 t->w->tagsafe = FALSE;
307 if(r == '\n')
308 t->w->tagexpand = TRUE;
309 winresize(w, w->r, TRUE, TRUE);
310 }
311 winunlock(w);
312 }
313 }
314 qunlock(&row->lk);
315 return t;
316}
317
318int
319rowclean(Row *row)
320{
321 int clean;
322 int i;
323
324 clean = TRUE;
325 for(i=0; i<row->ncol; i++)
326 clean &= colclean(row->col[i]);
327 return clean;
328}
329
330void
331rowdump(Row *row, char *file)
332{
333 int i, j, fd, m, n, dumped;
334 uint q0, q1;
335 Biobuf *b;
336 char *buf, *a, *fontname;
337 Rune *r;
338 Column *c;
339 Window *w, *w1;
340 Text *t;
341
342 if(row->ncol == 0)
343 return;
344 buf = fbufalloc();
345 if(file == nil){
346 if(home == nil){
347 warning(nil, "can't find file for dump: $home not defined\n");
348 goto Rescue;
349 }
350 sprint(buf, "%s", dumppath);
351 file = buf;
352 }
353 fd = create(file, OWRITE, 0600);
354 if(fd < 0){
355 warning(nil, "can't open %s: %r\n", file);
356 goto Rescue;
357 }
358 b = emalloc(sizeof(Biobuf));
359 Binit(b, fd, OWRITE);
360 r = fbufalloc();
361 Bprint(b, "%s\n", wdir);
362 Bprint(b, "%s\n", fontnames[0]);
363 Bprint(b, "%s\n", fontnames[1]);
364 for(i=0; i<row->ncol; i++){
365 c = row->col[i];
366 Bprint(b, "%11.7f", 100.0*(c->r.min.x-row->r.min.x)/Dx(row->r));
367 if(i == row->ncol-1)
368 Bputc(b, '\n');
369 else
370 Bputc(b, ' ');
371 }
372 for(i=0; i<row->ncol; i++){
373 c = row->col[i];
374 for(j=0; j<c->nw; j++)
375 c->w[j]->body.file->dumpid = 0;
376 }
377 m = min(RBUFSIZE, row->tag.file->b.nc);
378 bufread(&row->tag.file->b, 0, r, m);
379 n = 0;
380 while(n<m && r[n]!='\n')
381 n++;
382 Bprint(b, "w %.*S\n", n, r);
383 for(i=0; i<row->ncol; i++){
384 c = row->col[i];
385 m = min(RBUFSIZE, c->tag.file->b.nc);
386 bufread(&c->tag.file->b, 0, r, m);
387 n = 0;
388 while(n<m && r[n]!='\n')
389 n++;
390 Bprint(b, "c%11d %.*S\n", i, n, r);
391 }
392 for(i=0; i<row->ncol; i++){
393 c = row->col[i];
394 for(j=0; j<c->nw; j++){
395 w = c->w[j];
396 wincommit(w, &w->tag);
397 t = &w->body;
398 /* windows owned by others get special treatment */
399 if(w->nopen[QWevent] > 0)
400 if(w->dumpstr == nil)
401 continue;
402 /* zeroxes of external windows are tossed */
403 if(t->file->ntext > 1)
404 for(n=0; n<t->file->ntext; n++){
405 w1 = t->file->text[n]->w;
406 if(w == w1)
407 continue;
408 if(w1->nopen[QWevent])
409 goto Continue2;
410 }
411 fontname = "";
412 if(t->reffont->f != font)
413 fontname = t->reffont->f->name;
414 if(t->file->nname)
415 a = runetobyte(t->file->name, t->file->nname);
416 else
417 a = emalloc(1);
418 if(t->file->dumpid){
419 dumped = FALSE;
420 Bprint(b, "x%11d %11d %11d %11d %11.7f %s\n", i, t->file->dumpid,
421 w->body.q0, w->body.q1,
422 100.0*(w->r.min.y-c->r.min.y)/Dy(c->r),
423 fontname);
424 }else if(w->dumpstr){
425 dumped = FALSE;
426 Bprint(b, "e%11d %11d %11d %11d %11.7f %s\n", i, t->file->dumpid,
427 0, 0,
428 100.0*(w->r.min.y-c->r.min.y)/Dy(c->r),
429 fontname);
430 }else if((w->dirty==FALSE && access(a, 0)==0) || w->isdir){
431 dumped = FALSE;
432 t->file->dumpid = w->id;
433 Bprint(b, "f%11d %11d %11d %11d %11.7f %s\n", i, w->id,
434 w->body.q0, w->body.q1,
435 100.0*(w->r.min.y-c->r.min.y)/Dy(c->r),
436 fontname);
437 }else{
438 dumped = TRUE;
439 t->file->dumpid = w->id;
440 Bprint(b, "F%11d %11d %11d %11d %11.7f %11d %s\n", i, j,
441 w->body.q0, w->body.q1,
442 100.0*(w->r.min.y-c->r.min.y)/Dy(c->r),
443 w->body.file->b.nc, fontname);
444 }
445 free(a);
446 winctlprint(w, buf, 0);
447 Bwrite(b, buf, strlen(buf));
448 m = min(RBUFSIZE, w->tag.file->b.nc);
449 bufread(&w->tag.file->b, 0, r, m);
450 n = 0;
451 while(n<m && r[n]!='\n')
452 n++;
453 Bprint(b, "%.*S\n", n, r);
454 if(dumped){
455 q0 = 0;
456 q1 = t->file->b.nc;
457 while(q0 < q1){
458 n = q1 - q0;
459 if(n > BUFSIZE/UTFmax)
460 n = BUFSIZE/UTFmax;
461 bufread(&t->file->b, q0, r, n);
462 Bprint(b, "%.*S", n, r);
463 q0 += n;
464 }
465 }
466 if(w->dumpstr){
467 if(w->dumpdir)
468 Bprint(b, "%s\n%s\n", w->dumpdir, w->dumpstr);
469 else
470 Bprint(b, "\n%s\n", w->dumpstr);
471 }
472 Continue2:;
473 }
474 }
475 Bterm(b);
476 close(fd);
477 free(b);
478 fbuffree(r);
479
480 Rescue:
481 fbuffree(buf);
482}
483
484static
485char*
486rdline(Biobuf *b, int *linep)
487{
488 char *l;
489
490 l = Brdline(b, '\n');
491 if(l)
492 (*linep)++;
493 return l;
494}
495
496/*
497 * Get font names from load file so we don't load fonts we won't use
498 */
499void
500rowloadfonts(char *file)
501{
502 int i;
503 Biobuf *b;
504 char *l;
505
506 b = Bopen(file, OREAD);
507 if(b == nil)
508 return;
509 /* current directory */
510 l = Brdline(b, '\n');
511 if(l == nil)
512 goto Return;
513 /* global fonts */
514 for(i=0; i<2; i++){
515 l = Brdline(b, '\n');
516 if(l == nil)
517 goto Return;
518 l[Blinelen(b)-1] = 0;
519 if(*l && strcmp(l, fontnames[i])!=0){
520 free(fontnames[i]);
521 fontnames[i] = estrdup(l);
522 }
523 }
524 Return:
525 Bterm(b);
526}
527
528int
529rowload(Row *row, char *file, int initing)
530{
531 int i, j, line, y, nr, nfontr, n, ns, ndumped, dumpid, x, fd, done;
532 double percent;
533 Biobuf *b, *bout;
534 char *buf, *l, *t, *fontname;
535 Rune *r, *fontr;
536 int rune;
537 Column *c, *c1, *c2;
538 uint q0, q1;
539 Rectangle r1, r2;
540 Window *w;
541
542 buf = fbufalloc();
543 if(file == nil){
544 if(home == nil){
545 warning(nil, "can't find file for load: $home not defined\n");
546 goto Rescue1;
547 }
548 sprint(buf, "%s", dumppath);
549 file = buf;
550 }
551 b = Bopen(file, OREAD);
552 if(b == nil){
553 warning(nil, "can't open load file %s: %r\n", file);
554 goto Rescue1;
555 }
556 /* current directory */
557 line = 0;
558 l = rdline(b, &line);
559 if(l == nil)
560 goto Rescue2;
561 l[Blinelen(b)-1] = 0;
562 if(chdir(l) < 0){
563 warning(nil, "can't chdir %s\n", l);
564 goto Rescue2;
565 }
566 /* global fonts */
567 for(i=0; i<2; i++){
568 l = rdline(b, &line);
569 if(l == nil)
570 goto Rescue2;
571 l[Blinelen(b)-1] = 0;
572 if(*l && strcmp(l, fontnames[i])!=0)
573 rfget(i, TRUE, i==0 && initing, l);
574 }
575 if(initing && row->ncol==0)
576 rowinit(row, screen->clipr);
577 l = rdline(b, &line);
578 if(l == nil)
579 goto Rescue2;
580 j = Blinelen(b)/12;
581 if(j<=0 || j>10)
582 goto Rescue2;
583 for(i=0; i<j; i++){
584 percent = atof(l+i*12);
585 if(percent<0 || percent>=100)
586 goto Rescue2;
587 x = row->r.min.x+percent*Dx(row->r)/100+0.5;
588 if(i < row->ncol){
589 if(i == 0)
590 continue;
591 c1 = row->col[i-1];
592 c2 = row->col[i];
593 r1 = c1->r;
594 r2 = c2->r;
595 if(x<Border)
596 x = Border;
597 r1.max.x = x-Border;
598 r2.min.x = x;
599 if(Dx(r1) < 50 || Dx(r2) < 50)
600 continue;
601 draw(screen, Rpt(r1.min, r2.max), bordercol, nil, ZP);
602 colresize(c1, r1);
603 colresize(c2, r2);
604 r2.min.x = x-Border;
605 r2.max.x = x;
606 draw(screen, r2, bordercol, nil, ZP);
607 }
608 if(i >= row->ncol)
609 rowadd(row, nil, x);
610 }
611 done = 0;
612 while(!done){
613 l = rdline(b, &line);
614 if(l == nil)
615 break;
616 switch(l[0]){
617 case 'c':
618 l[Blinelen(b)-1] = 0;
619 i = atoi(l+1+0*12);
620 r = bytetorune(l+1*12, &nr);
621 ns = -1;
622 for(n=0; n<nr; n++){
623 if(r[n] == '/')
624 ns = n;
625 if(r[n] == ' ')
626 break;
627 }
628 textdelete(&row->col[i]->tag, 0, row->col[i]->tag.file->b.nc, TRUE);
629 textinsert(&row->col[i]->tag, 0, r+n+1, nr-(n+1), TRUE);
630 break;
631 case 'w':
632 l[Blinelen(b)-1] = 0;
633 r = bytetorune(l+2, &nr);
634 ns = -1;
635 for(n=0; n<nr; n++){
636 if(r[n] == '/')
637 ns = n;
638 if(r[n] == ' ')
639 break;
640 }
641 textdelete(&row->tag, 0, row->tag.file->b.nc, TRUE);
642 textinsert(&row->tag, 0, r, nr, TRUE);
643 break;
644 default:
645 done = 1;
646 break;
647 }
648 }
649 for(;;){
650 if(l == nil)
651 break;
652 dumpid = 0;
653 switch(l[0]){
654 case 'e':
655 if(Blinelen(b) < 1+5*12+1)
656 goto Rescue2;
657 l = rdline(b, &line); /* ctl line; ignored */
658 if(l == nil)
659 goto Rescue2;
660 l = rdline(b, &line); /* directory */
661 if(l == nil)
662 goto Rescue2;
663 l[Blinelen(b)-1] = 0;
664 if(*l == '\0'){
665 if(home == nil)
666 r = bytetorune("./", &nr);
667 else{
668 t = emalloc(strlen(home)+1+1);
669 sprint(t, "%s/", home);
670 r = bytetorune(t, &nr);
671 free(t);
672 }
673 }else
674 r = bytetorune(l, &nr);
675 l = rdline(b, &line); /* command */
676 if(l == nil)
677 goto Rescue2;
678 t = emalloc(Blinelen(b)+1);
679 memmove(t, l, Blinelen(b));
680 run(nil, t, r, nr, TRUE, nil, nil, FALSE);
681 /* r is freed in run() */
682 goto Nextline;
683 case 'f':
684 if(Blinelen(b) < 1+5*12+1)
685 goto Rescue2;
686 fontname = l+1+5*12;
687 ndumped = -1;
688 break;
689 case 'F':
690 if(Blinelen(b) < 1+6*12+1)
691 goto Rescue2;
692 fontname = l+1+6*12;
693 ndumped = atoi(l+1+5*12+1);
694 break;
695 case 'x':
696 if(Blinelen(b) < 1+5*12+1)
697 goto Rescue2;
698 fontname = l+1+5*12;
699 ndumped = -1;
700 dumpid = atoi(l+1+1*12);
701 break;
702 default:
703 goto Rescue2;
704 }
705 l[Blinelen(b)-1] = 0;
706 fontr = nil;
707 nfontr = 0;
708 if(*fontname)
709 fontr = bytetorune(fontname, &nfontr);
710 i = atoi(l+1+0*12);
711 j = atoi(l+1+1*12);
712 q0 = atoi(l+1+2*12);
713 q1 = atoi(l+1+3*12);
714 percent = atof(l+1+4*12);
715 if(i<0 || i>10)
716 goto Rescue2;
717 if(i > row->ncol)
718 i = row->ncol;
719 c = row->col[i];
720 y = c->r.min.y+(percent*Dy(c->r))/100+0.5;
721 if(y<c->r.min.y || y>=c->r.max.y)
722 y = -1;
723 if(dumpid == 0)
724 w = coladd(c, nil, nil, y);
725 else
726 w = coladd(c, nil, lookid(dumpid, TRUE), y);
727 if(w == nil)
728 goto Nextline;
729 w->dumpid = j;
730 l = rdline(b, &line);
731 if(l == nil)
732 goto Rescue2;
733 l[Blinelen(b)-1] = 0;
734 r = bytetorune(l+5*12, &nr);
735 ns = -1;
736 for(n=0; n<nr; n++){
737 if(r[n] == '/')
738 ns = n;
739 if(r[n] == ' ')
740 break;
741 }
742 if(dumpid == 0)
743 winsetname(w, r, n);
744 for(; n<nr; n++)
745 if(r[n] == '|')
746 break;
747 wincleartag(w);
748 textinsert(&w->tag, w->tag.file->b.nc, r+n+1, nr-(n+1), TRUE);
749 if(ndumped >= 0){
750 /* simplest thing is to put it in a file and load that */
751 sprint(buf, "/tmp/d%d.%.4sacme", PID, getuser());
752 fd = create(buf, OWRITE, 0600);
753 if(fd < 0){
754 free(r);
755 warning(nil, "can't create temp file: %r\n");
756 goto Rescue2;
757 }
758 bout = emalloc(sizeof(Biobuf));
759 Binit(bout, fd, OWRITE);
760 for(n=0; n<ndumped; n++){
761 rune = Bgetrune(b);
762 if(rune == '\n')
763 line++;
764 if(rune == Beof){
765 free(r);
766 Bterm(bout);
767 free(bout);
768 close(fd);
769 remove(buf);
770 goto Rescue2;
771 }
772 Bputrune(bout, rune);
773 }
774 Bterm(bout);
775 free(bout);
776 textload(&w->body, 0, buf, 1);
777 remove(buf);
778 close(fd);
779 w->body.file->mod = TRUE;
780 for(n=0; n<w->body.file->ntext; n++)
781 w->body.file->text[n]->w->dirty = TRUE;
782 winsettag(w);
783 }else if(dumpid==0 && r[ns+1]!='+' && r[ns+1]!='-')
784 get(&w->body, nil, nil, FALSE, XXX, nil, 0);
785 if(fontr){
786 fontx(&w->body, nil, nil, 0, 0, fontr, nfontr);
787 free(fontr);
788 }
789 free(r);
790 if(q0>w->body.file->b.nc || q1>w->body.file->b.nc || q0>q1)
791 q0 = q1 = 0;
792 textshow(&w->body, q0, q1, 1);
793 w->maxlines = min(w->body.fr.nlines, max(w->maxlines, w->body.fr.maxlines));
794 xfidlog(w, "new");
795Nextline:
796 l = rdline(b, &line);
797 }
798 Bterm(b);
799 fbuffree(buf);
800 return TRUE;
801
802Rescue2:
803 warning(nil, "bad load file %s:%d\n", file, line);
804 Bterm(b);
805Rescue1:
806 fbuffree(buf);
807 return FALSE;
808}
809
810void
811allwindows(void (*f)(Window*, void*), void *arg)
812{
813 int i, j;
814 Column *c;
815
816 for(i=0; i<row.ncol; i++){
817 c = row.col[i];
818 for(j=0; j<c->nw; j++)
819 (*f)(c->w[j], arg);
820 }
821}