rows.c 14 KB

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