home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume26 / screen-3.5 / part05 / display.c next >
C/C++ Source or Header  |  1993-07-25  |  27KB  |  1,496 lines

  1. /* Copyright (c) 1993
  2.  *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
  3.  *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
  4.  * Copyright (c) 1987 Oliver Laumann
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2, or (at your option)
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program (see the file COPYING); if not, write to the
  18.  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  ****************************************************************
  21.  */
  22.  
  23. #include "rcs.h"
  24. RCS_ID("$Id: display.c,v 1.8 1993/07/21 15:43:02 mlschroe Exp $ FAU")
  25.  
  26.  
  27. #include <sys/types.h>
  28. #include <fcntl.h>
  29.  
  30. #include "config.h"
  31. #include "screen.h"
  32. #include "extern.h"
  33.  
  34. static void CountChars __P((int));
  35. static void PutChar __P((int));
  36. static int  BlankResize __P((int, int));
  37.  
  38.  
  39. extern char *tgoto __P((char *, int, int));
  40.  
  41. extern struct win *windows;
  42.  
  43. extern int  use_hardstatus;
  44. extern int  MsgMinWait;
  45. extern int  Z0width, Z1width;
  46. extern char *blank, *null;
  47.  
  48. /*
  49.  * tputs needs this to calculate the padding
  50.  */
  51. #ifndef NEED_OSPEED
  52. extern
  53. #endif /* NEED_OSPEED */
  54. short ospeed;
  55.  
  56.  
  57. struct display *display, *displays;
  58.  
  59. #ifndef MULTI
  60. struct display TheDisplay;
  61. #endif
  62.  
  63.  
  64. /*
  65.  *  The default values
  66.  */
  67. int defobuflimit = OBUF_MAX;
  68. #ifdef AUTO_NUKE
  69. int defautonuke = 0;
  70. #endif
  71.  
  72. /*
  73.  *  Default layer management
  74.  */
  75.  
  76. void
  77. DefProcess(bufp, lenp)
  78. char **bufp;
  79. int *lenp;
  80. {
  81.   *bufp += *lenp;
  82.   *lenp = 0;
  83. }
  84.  
  85. void
  86. DefRedisplayLine(y, xs, xe, isblank)
  87. int y, xs, xe, isblank;
  88. {
  89.   if (isblank == 0 && y >= 0)
  90.     DefClearLine(y, xs, xe);
  91. }
  92.  
  93. void
  94. DefClearLine(y, xs, xe)
  95. int y, xs, xe;
  96. {
  97.   DisplayLine(null, null, null, blank, null, null, y, xs, xe);
  98. }
  99.  
  100. /*ARGSUSED*/
  101. int
  102. DefRewrite(y, xs, xe, doit)
  103. int y, xs, xe, doit;
  104. {
  105.   return EXPENSIVE;
  106. }
  107.  
  108. void
  109. DefSetCursor()
  110. {
  111.   GotoPos(0, 0);
  112. }
  113.  
  114. /*ARGSUSED*/
  115. int
  116. DefResize(wi, he)
  117. int wi, he;
  118. {
  119.   return -1;
  120. }
  121.  
  122. void
  123. DefRestore()
  124. {
  125.   InsertMode(0);
  126.   ChangeScrollRegion(0, d_height - 1);
  127.   KeypadMode(0);
  128.   CursorkeysMode(0);
  129.   SetAttrFont(0, ASCII);
  130.   SetFlow(FLOW_NOW);
  131. }
  132.  
  133. /*
  134.  *  Blank layer management
  135.  */
  136.  
  137. struct LayFuncs BlankLf =
  138. {
  139.   DefProcess,
  140.   0,
  141.   DefRedisplayLine,
  142.   DefClearLine,
  143.   DefRewrite,
  144.   DefSetCursor,
  145.   BlankResize,
  146.   DefRestore
  147. };
  148.  
  149. struct layer BlankLayer =
  150. {
  151.   0,
  152.   0,
  153.   &BlankLf,
  154.   0
  155. };
  156.  
  157. /*ARGSUSED*/
  158. static int
  159. BlankResize(wi, he)
  160. int wi, he;
  161. {
  162.   return 0;
  163. }
  164.  
  165.  
  166. /*
  167.  *  Generate new display
  168.  */
  169.  
  170. struct display *
  171. MakeDisplay(uname, utty, term, fd, pid, Mode)
  172. char *uname, *utty, *term;
  173. int fd, pid;
  174. struct mode *Mode;
  175. {
  176.   struct user **u;
  177.  
  178. #ifdef MULTI
  179.   if ((display = (struct display *)malloc(sizeof(*display))) == 0)
  180.     return 0;
  181.   bzero((char *) display, sizeof(*display));
  182. #else
  183.   if (displays)
  184.     return 0;
  185.   display = &TheDisplay;
  186. #endif
  187.   display->_d_next = displays;
  188.   displays = display;
  189.   d_flow = 1;
  190.   d_userfd = fd;
  191.   d_OldMode = *Mode;
  192.   Resize_obuf();  /* Allocate memory for buffer */
  193.   d_obufmax = defobuflimit;
  194. #ifdef AUTO_NUKE
  195.   d_auto_nuke = defautonuke;
  196. #endif
  197.   d_obufp = d_obuf;
  198.   d_userpid = pid;
  199. #ifdef POSIX
  200.   d_dospeed = (short) cfgetospeed(&d_OldMode.tio);
  201. #else
  202. # ifndef TERMIO
  203.   d_dospeed = (short) d_OldMode.m_ttyb.sg_ospeed;
  204. # endif
  205. #endif
  206.   debug1("New displays ospeed = %d\n", d_dospeed);
  207.   strcpy(d_usertty, utty);
  208.   strcpy(d_termname, term);
  209.  
  210.   if (!*(u = FindUserPtr(uname)) && UserAdd(uname, NULL, u))
  211.     {
  212.       FreeDisplay();
  213.       return NULL;    /* could not find or add user */
  214.     }
  215.   d_user = *u;
  216.   d_lay = &BlankLayer;
  217.   d_layfn = BlankLayer.l_layfn;
  218.   return display;
  219. }
  220.  
  221. void
  222. FreeDisplay()
  223. {
  224. #ifdef MULTI
  225.   struct display *d, **dp;
  226.  
  227.   for (dp = &displays; (d = *dp) ; dp = &d->_d_next)
  228.     if (d == display)
  229.       break;
  230.   ASSERT(d);
  231.   if (d_status_lastmsg)
  232.     free(d_status_lastmsg);
  233. # ifdef COPY_PASTE
  234.   if (d_copybuffer)
  235.     free(d_copybuffer);
  236. # endif
  237.   if (d_obuf)
  238.     free(d_obuf);
  239.   *dp = display->_d_next;
  240.   free(display);
  241. #else /* MULTI */
  242.   ASSERT(display == displays);
  243.   ASSERT(display == &TheDisplay);
  244.   displays = 0;
  245. #endif /* MULTI */
  246.   display = 0;
  247. }
  248.  
  249. /*
  250.  * if the adaptflag is on, we keep the size of this display, else
  251.  * we may try to restore our old window sizes.
  252.  */
  253. void
  254. InitTerm(adapt)
  255. int adapt;
  256. {
  257.   ASSERT(display);
  258.   d_top = d_bot = -1;
  259.   PutStr(TI);
  260.   PutStr(IS);
  261.   /* Check for toggle */
  262.   if (IM && strcmp(IM, EI))
  263.     PutStr(EI);
  264.   d_insert = 0;
  265.   /* Check for toggle */
  266.   if (KS && strcmp(KS, KE))
  267.     PutStr(KE);
  268.   d_keypad = 0;
  269.   if (CCS && strcmp(CCS, CCE))
  270.     PutStr(CCE);
  271.   d_cursorkeys = 0;
  272.   PutStr(CE0);
  273.   d_font = ASCII;
  274.   if (adapt == 0)
  275.     ResizeDisplay(d_defwidth, d_defheight);
  276.   ChangeScrollRegion(0, d_height - 1);
  277.   d_x = d_y = 0;
  278.   Flush();
  279.   ClearDisplay();
  280.   debug1("we %swant to adapt all our windows to the display\n", 
  281.      (adapt) ? "" : "don't ");
  282.   /* In case the size was changed by a init sequence */
  283.   CheckScreenSize((adapt) ? 2 : 0);
  284. }
  285.  
  286. void
  287. FinitTerm()
  288. {
  289.   ASSERT(display);
  290.   ResizeDisplay(d_defwidth, d_defheight);
  291.   DefRestore();
  292.   SetAttrFont(0, ASCII);
  293.   d_x = d_y = -1;
  294.   GotoPos(0, d_height - 1);
  295.   AddChar('\n');
  296.   PutStr(TE);
  297.   Flush();
  298. }
  299.  
  300.  
  301. void
  302. INSERTCHAR(c)
  303. int c;
  304. {
  305.   ASSERT(display);
  306.   if (!d_insert && d_x < d_width - 1)
  307.     {
  308.       if (IC || CIC)
  309.     {
  310.       if (IC)
  311.         PutStr(IC);
  312.       else
  313.         CPutStr(CIC, 1);
  314.       RAW_PUTCHAR(c);
  315.       return;
  316.     }
  317.       InsertMode(1);
  318.       if (!d_insert)
  319.     {
  320.           RefreshLine(d_y, d_x, d_width-1, 0);
  321.       return;
  322.     }
  323.     }
  324.   RAW_PUTCHAR(c);
  325. }
  326.  
  327. void
  328. PUTCHAR(c)
  329. int c;
  330. {
  331.   ASSERT(display);
  332.   if (d_insert && d_x < d_width - 1)
  333.     InsertMode(0);
  334.   RAW_PUTCHAR(c);
  335. }
  336.  
  337. void
  338. PUTCHARLP(c)
  339. int c;
  340. {
  341.   if (d_x < d_width - 1)
  342.     {
  343.       if (d_insert)
  344.     InsertMode(0);
  345.       RAW_PUTCHAR(c);
  346.       return;
  347.     }
  348.   if (CLP || d_y != d_bot)
  349.     {
  350.       RAW_PUTCHAR(c);
  351.       return;
  352.     }
  353.   d_lp_missing = 1;
  354.   d_lp_image = c;
  355.   d_lp_attr = d_attr;
  356.   d_lp_font = d_font;
  357. }
  358.  
  359. /*
  360.  * RAW_PUTCHAR() is for all text that will be displayed.
  361.  * NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
  362.  */
  363.  
  364. void
  365. RAW_PUTCHAR(c)
  366. int c;
  367. {
  368.   ASSERT(display);
  369.   if (d_font == '0')
  370.     {
  371.       AddChar(d_c0_tab[c]);
  372.     }
  373.   else
  374.     AddChar(c);
  375.   if (++d_x >= d_width)
  376.     {
  377.       if ((AM && !CLP) || d_x > d_width)
  378.     {
  379.       d_x -= d_width;
  380.       if (d_y < d_height-1 && d_y != d_bot)
  381.         d_y++;
  382.     }
  383.     }
  384. }
  385.  
  386. static void
  387. PutChar(c)
  388. int c;
  389. {
  390.   /* this PutChar for ESC-sequences only (AddChar is a macro) */
  391.   AddChar(c);
  392. }
  393.  
  394. void
  395. PutStr(s)
  396. char *s;
  397. {
  398.   if (display && s)
  399.     {
  400.       ospeed = d_dospeed;
  401.       tputs(s, 1, PutChar);
  402.     }
  403. }
  404.  
  405. void
  406. CPutStr(s, c)
  407. char *s;
  408. int c;
  409. {
  410.   if (display && s)
  411.     {
  412.       ospeed = d_dospeed;
  413.       tputs(tgoto(s, 0, c), 1, PutChar);
  414.     }
  415. }
  416.  
  417.  
  418. /* Insert mode is a toggle on some terminals, so we need this hack:
  419.  */
  420. void
  421. InsertMode(on)
  422. int on;
  423. {
  424.   if (display && on != d_insert && IM)
  425.     {
  426.       d_insert = on;
  427.       if (d_insert)
  428.     PutStr(IM);
  429.       else
  430.     PutStr(EI);
  431.     }
  432. }
  433.  
  434. /* ...and maybe d_keypad application mode is a toggle, too:
  435.  */
  436. void
  437. KeypadMode(on)
  438. int on;
  439. {
  440.   if (display && d_keypad != on && KS)
  441.     {
  442.       d_keypad = on;
  443.       if (d_keypad)
  444.     PutStr(KS);
  445.       else
  446.     PutStr(KE);
  447.     }
  448. }
  449.  
  450. void
  451. CursorkeysMode(on)
  452. int on;
  453. {
  454.   if (display && d_cursorkeys != on && CCS)
  455.     {
  456.       d_cursorkeys = on;
  457.       if (d_cursorkeys)
  458.     PutStr(CCS);
  459.       else
  460.     PutStr(CCE);
  461.     }
  462. }
  463.  
  464. static int StrCost;
  465.  
  466. /* ARGSUSED */
  467. static void
  468. CountChars(c)
  469. int c;
  470. {
  471.   StrCost++;
  472. }
  473.  
  474. int
  475. CalcCost(s)
  476. register char *s;
  477. {
  478.   ASSERT(display);
  479.   if (s)
  480.     {
  481.       StrCost = 0;
  482.       ospeed = d_dospeed;
  483.       tputs(s, 1, CountChars);
  484.       return StrCost;
  485.     }
  486.   else
  487.     return EXPENSIVE;
  488. }
  489.  
  490. void
  491. GotoPos(x2, y2)
  492. int x2, y2;
  493. {
  494.   register int dy, dx, x1, y1;
  495.   register int costx, costy;
  496.   register int m;
  497.   register char *s;
  498.   int CMcost;
  499.   enum move_t xm = M_NONE, ym = M_NONE;
  500.  
  501.   if (!display)
  502.     return;
  503.  
  504.   x1 = d_x;
  505.   y1 = d_y;
  506.  
  507.   if (x1 == d_width)
  508.     if (CLP && AM)
  509.       x1 = -1;        /* don't know how the terminal treats this */
  510.     else
  511.       x1--;
  512.   if (x2 == d_width)
  513.     x2--;
  514.   dx = x2 - x1;
  515.   dy = y2 - y1;
  516.   if (dy == 0 && dx == 0)
  517.     {
  518.       return;
  519.     }
  520.   if (!MS && d_attr)    /* Safe to move in SO mode ? */
  521.     SetAttr(0);
  522.   if (y1 < 0            /* don't know the y position */
  523.       || (y2 > d_bot && y1 <= d_bot)    /* have to cross border */
  524.       || (y2 < d_top && y1 >= d_top))    /* of scrollregion ?    */
  525.     {
  526.     DoCM:
  527.       if (HO && !x2 && !y2)
  528.         PutStr(HO);
  529.       else
  530.         PutStr(tgoto(CM, x2, y2));
  531.       d_x = x2;
  532.       d_y = y2;
  533.       return;
  534.     }
  535.   /* Calculate CMcost */
  536.   if (HO && !x2 && !y2)
  537.     s = HO;
  538.   else
  539.     s = tgoto(CM, x2, y2);
  540.   CMcost = CalcCost(s);
  541.  
  542.   /* Calculate the cost to move the cursor to the right x position */
  543.   costx = EXPENSIVE;
  544.   if (x1 >= 0)    /* relativ x positioning only if we know where we are */
  545.     {
  546.       if (dx > 0)
  547.     {
  548.       if (CRI && (dx > 1 || !ND))
  549.         {
  550.           costx = CalcCost(tgoto(CRI, 0, dx));
  551.           xm = M_CRI;
  552.         }
  553.       if ((m = d_NDcost * dx) < costx)
  554.         {
  555.           costx = m;
  556.           xm = M_RI;
  557.         }
  558.       /* Speedup: dx <= Rewrite() */
  559.       if (dx < costx && (m = Rewrite(y1, x1, x2, 0)) < costx)
  560.         {
  561.           costx = m;
  562.           xm = M_RW;
  563.         }
  564.     }
  565.       else if (dx < 0)
  566.     {
  567.       if (CLE && (dx < -1 || !BC))
  568.         {
  569.           costx = CalcCost(tgoto(CLE, 0, -dx));
  570.           xm = M_CLE;
  571.         }
  572.       if ((m = -dx * d_LEcost) < costx)
  573.         {
  574.           costx = m;
  575.           xm = M_LE;
  576.         }
  577.     }
  578.       else
  579.     costx = 0;
  580.     }
  581.   /* Speedup: Rewrite() >= x2 */
  582.   if (x2 + d_CRcost < costx && (m = (x2 ? Rewrite(y1, 0, x2, 0) : 0) + d_CRcost) < costx)
  583.     {
  584.       costx = m;
  585.       xm = M_CR;
  586.     }
  587.  
  588.   /* Check if it is already cheaper to do CM */
  589.   if (costx >= CMcost)
  590.     goto DoCM;
  591.  
  592.   /* Calculate the cost to move the cursor to the right y position */
  593.   costy = EXPENSIVE;
  594.   if (dy > 0)
  595.     {
  596.       if (CDO && dy > 1)    /* DO & NL are always != 0 */
  597.     {
  598.       costy = CalcCost(tgoto(CDO, 0, dy));
  599.       ym = M_CDO;
  600.     }
  601.       if ((m = dy * ((x2 == 0) ? d_NLcost : d_DOcost)) < costy)
  602.     {
  603.       costy = m;
  604.       ym = M_DO;
  605.     }
  606.     }
  607.   else if (dy < 0)
  608.     {
  609.       if (CUP && (dy < -1 || !UP))
  610.     {
  611.       costy = CalcCost(tgoto(CUP, 0, -dy));
  612.       ym = M_CUP;
  613.     }
  614.       if ((m = -dy * d_UPcost) < costy)
  615.     {
  616.       costy = m;
  617.       ym = M_UP;
  618.     }
  619.     }
  620.   else
  621.     costy = 0;
  622.  
  623.   /* Finally check if it is cheaper to do CM */
  624.   if (costx + costy >= CMcost)
  625.     goto DoCM;
  626.  
  627.   switch (xm)
  628.     {
  629.     case M_LE:
  630.       while (dx++ < 0)
  631.     PutStr(BC);
  632.       break;
  633.     case M_CLE:
  634.       CPutStr(CLE, -dx);
  635.       break;
  636.     case M_RI:
  637.       while (dx-- > 0)
  638.     PutStr(ND);
  639.       break;
  640.     case M_CRI:
  641.       CPutStr(CRI, dx);
  642.       break;
  643.     case M_CR:
  644.       PutStr(CR);
  645.       d_x = 0;
  646.       x1 = 0;
  647.       /* FALLTHROUGH */
  648.     case M_RW:
  649.       if (x1 < x2)
  650.     (void) Rewrite(y1, x1, x2, 1);
  651.       break;
  652.     default:
  653.       break;
  654.     }
  655.  
  656.   switch (ym)
  657.     {
  658.     case M_UP:
  659.       while (dy++ < 0)
  660.     PutStr(UP);
  661.       break;
  662.     case M_CUP:
  663.       CPutStr(CUP, -dy);
  664.       break;
  665.     case M_DO:
  666.       s =  (x2 == 0) ? NL : DO;
  667.       while (dy-- > 0)
  668.     PutStr(s);
  669.       break;
  670.     case M_CDO:
  671.       CPutStr(CDO, dy);
  672.       break;
  673.     default:
  674.       break;
  675.     }
  676.   d_x = x2;
  677.   d_y = y2;
  678. }
  679.  
  680. void
  681. ClearDisplay()
  682. {
  683.   ASSERT(display);
  684.   Clear(0, 0, d_width - 1, d_height - 1);
  685. }
  686.  
  687. void
  688. Clear(xs, ys, xe, ye)
  689. int xs, ys, xe, ye;
  690. {
  691.   int y, xxe;
  692.  
  693.   ASSERT(display);
  694.   if (xs == d_width)
  695.     xs--;
  696.   if (xe == d_width)
  697.     xe--;
  698.   if (d_lp_missing && ys <= d_bot)
  699.     {
  700.       if (ye > d_bot || (ye == d_bot && xe == d_width - 1))
  701.     d_lp_missing = 0;
  702.     }
  703.   if (xe == d_width - 1 && ye == d_height - 1)
  704.     {
  705. #ifdef AUTO_NUKE
  706.       if (xs == 0 && ys == 0 && d_auto_nuke)
  707.     NukePending();
  708. #endif
  709.       if (xs == 0 && ys == 0 && CL)
  710.     {
  711.       PutStr(CL);
  712.       d_y = d_x = 0;
  713.       return;
  714.     }
  715.       /* 
  716.        * Workaround a hp700/22 terminal bug. Do not use CD where CE
  717.        * is also appropriate.
  718.        */
  719.       if (CD && (ys < ye || !CE))
  720.     {
  721.       GotoPos(xs, ys);
  722.       PutStr(CD);
  723.       return;
  724.     }
  725.     }
  726.   xxe = d_width - 1;
  727.   for (y = ys; y <= ye; y++, xs = 0)
  728.     {
  729.       if (y == ye)
  730.     xxe = xe;
  731.       if (xs == 0 && CB && (xxe != d_width - 1 || (d_x == xxe && d_y == y)))
  732.     {
  733.       GotoPos(xxe, y);
  734.       PutStr(CB);
  735.       continue;
  736.     }
  737.       if (xxe == d_width - 1 && CE)
  738.     {
  739.       GotoPos(xs, y);
  740.       PutStr(CE);
  741.       continue;
  742.     }
  743.       ClearLine(y, xs, xxe);
  744.     }
  745. }
  746.  
  747.  
  748. /*
  749.  * if cur_only > 0, we only redisplay current line, as a full refresh is
  750.  * too expensive over a low baud line.
  751.  */
  752. void
  753. Redisplay(cur_only)
  754. int cur_only;
  755. {
  756.   register int i, stop;
  757.  
  758.   ASSERT(display);
  759.   DefRestore();
  760.   ClearDisplay();
  761.   stop = d_height;
  762.   i = 0;
  763.   if (cur_only > 0 && d_fore)
  764.     {
  765.       i = stop = d_fore->w_y;
  766.       stop++;
  767.     }
  768.   else RedisplayLine(-1, 0, d_width - 1, 1);
  769.   for (; i < stop; i++)
  770.     RedisplayLine(i, 0, d_width - 1, 1);
  771.   Restore();
  772.   SetCursor();
  773. }
  774.  
  775.  
  776. void
  777. ScrollRegion(ys, ye, n)
  778. int ys, ye, n;
  779. {
  780.   int i;
  781.   int up;
  782.   int oldtop, oldbot;
  783.   int alok, dlok, aldlfaster;
  784.   int missy = 0;
  785.  
  786.   ASSERT(display);
  787.   if (n == 0)
  788.     return;
  789.   if (ys == 0 && ye == d_height - 1 && 
  790.       (n >= d_height || -n >= d_height))
  791.     {
  792.       ClearDisplay();
  793.       return;
  794.     }
  795.  
  796.   if (d_lp_missing)
  797.     {
  798.       if (d_bot > ye || d_bot < ys)
  799.     missy = d_bot;
  800.       else
  801.     {
  802.       missy = d_bot - n;
  803.           if (missy>ye || missy<ys)
  804.         d_lp_missing = 0;
  805.     }
  806.     }
  807.  
  808.   up = 1;
  809.   if (n < 0)
  810.     {
  811.       up = 0;
  812.       n = -n;
  813.     }
  814.   if (n >= ye-ys+1)
  815.     n = ye-ys+1;
  816.  
  817.   oldtop = d_top;
  818.   oldbot = d_bot;
  819.   if (d_bot != ye)
  820.     ChangeScrollRegion(ys, ye);
  821.   alok = (AL || CAL || (ye == d_bot &&  up));
  822.   dlok = (DL || CDL || (ye == d_bot && !up));
  823.   if (d_top != ys && !(alok && dlok))
  824.     ChangeScrollRegion(ys, ye);
  825.  
  826.   if (d_lp_missing && 
  827.       (oldbot != d_bot ||
  828.        (oldbot == d_bot && up && d_top == ys && d_bot == ye)))
  829.     {
  830.       FixLP(d_width - 1, oldbot);
  831.       if (oldbot == d_bot)        /* have scrolled */
  832.     {
  833.       if (--n == 0)
  834.         {
  835.           ChangeScrollRegion(oldtop, oldbot);
  836.           return;
  837.         }
  838.     }
  839.     }
  840.  
  841.   aldlfaster = (n > 1 && ye == d_bot && ((up && CDL) || (!up && CAL)));
  842.  
  843.   if ((up || SR) && d_top == ys && d_bot == ye && !aldlfaster)
  844.     {
  845.       if (up)
  846.     {
  847.       GotoPos(0, ye);
  848.       while (n-- > 0)
  849.         PutStr(NL);        /* was SF, I think NL is faster */
  850.     }
  851.       else
  852.     {
  853.       GotoPos(0, ys);
  854.       while (n-- > 0)
  855.         PutStr(SR);
  856.     }
  857.     }
  858.   else if (alok && dlok)
  859.     {
  860.       if (up || ye != d_bot)
  861.     {
  862.           GotoPos(0, up ? ys : ye+1-n);
  863.           if (CDL && !(n == 1 && DL))
  864.         CPutStr(CDL, n);
  865.       else
  866.         for(i = n; i--; )
  867.           PutStr(DL);
  868.     }
  869.       if (!up || ye != d_bot)
  870.     {
  871.           GotoPos(0, up ? ye+1-n : ys);
  872.           if (CAL && !(n == 1 && AL))
  873.         CPutStr(CAL, n);
  874.       else
  875.         for(i = n; i--; )
  876.           PutStr(AL);
  877.     }
  878.     }
  879.   else
  880.     {
  881.       Redisplay(0);
  882.       return;
  883.     }
  884.   if (d_lp_missing && missy != d_bot)
  885.     FixLP(d_width - 1, missy);
  886.   ChangeScrollRegion(oldtop, oldbot);
  887.   if (d_lp_missing && missy != d_bot)
  888.     FixLP(d_width - 1, missy);
  889. }
  890.  
  891. void
  892. SetAttr(new)
  893. register int new;
  894. {
  895.   register int i, old;
  896.  
  897.   if (!display || (old = d_attr) == new)
  898.     return;
  899.   d_attr = new;
  900.   for (i = 1; i <= A_MAX; i <<= 1)
  901.     {
  902.       if ((old & i) && !(new & i))
  903.     {
  904.       PutStr(UE);
  905.       PutStr(SE);
  906.       PutStr(ME);
  907.       if (new & A_DI)
  908.         PutStr(d_attrtab[ATTR_DI]);
  909.       if (new & A_US)
  910.         PutStr(d_attrtab[ATTR_US]);
  911.       if (new & A_BD)
  912.         PutStr(d_attrtab[ATTR_BD]);
  913.       if (new & A_RV)
  914.         PutStr(d_attrtab[ATTR_RV]);
  915.       if (new & A_SO)
  916.         PutStr(d_attrtab[ATTR_SO]);
  917.       if (new & A_BL)
  918.         PutStr(d_attrtab[ATTR_BL]);
  919.       return;
  920.     }
  921.     }
  922.   if ((new & A_DI) && !(old & A_DI))
  923.     PutStr(d_attrtab[ATTR_DI]);
  924.   if ((new & A_US) && !(old & A_US))
  925.     PutStr(d_attrtab[ATTR_US]);
  926.   if ((new & A_BD) && !(old & A_BD))
  927.     PutStr(d_attrtab[ATTR_BD]);
  928.   if ((new & A_RV) && !(old & A_RV))
  929.     PutStr(d_attrtab[ATTR_RV]);
  930.   if ((new & A_SO) && !(old & A_SO))
  931.     PutStr(d_attrtab[ATTR_SO]);
  932.   if ((new & A_BL) && !(old & A_BL))
  933.     PutStr(d_attrtab[ATTR_BL]);
  934. }
  935.  
  936. void
  937. SetFont(new)
  938. int new;
  939. {
  940.   if (!display || d_font == new)
  941.     return;
  942.   d_font = new;
  943.   if (new == ASCII)
  944.     PutStr(CE0);
  945.   else
  946.     CPutStr(CS0, new);
  947. }
  948.  
  949. void
  950. SetAttrFont(newattr, newcharset)
  951. int newattr, newcharset;
  952. {
  953.   SetAttr(newattr);
  954.   SetFont(newcharset);
  955. }
  956.  
  957. void
  958. MakeStatus(msg)
  959. char *msg;
  960. {
  961.   register char *s, *t;
  962.   register int max, ti;
  963.  
  964.   if (!display)
  965.     return;
  966.   
  967.   if (!d_tcinited)
  968.     {
  969.       debug("tc not inited, just writing msg\n");
  970.       AddStr(msg);
  971.       AddStr("\r\n");
  972.       Flush();
  973.       return;
  974.     }
  975.   if (!use_hardstatus || !HS)
  976.     {
  977.       max = d_width;
  978.       if (CLP == 0)
  979.     max--;
  980.     }
  981.   else
  982.     max = WS;
  983.   if (d_status)
  984.     {
  985.       if (!d_status_bell)
  986.     {
  987.       ti = time((time_t *) 0) - d_status_time;
  988.       if (ti < MsgMinWait)
  989.         sleep(MsgMinWait - ti);
  990.     }
  991.       RemoveStatus();
  992.     }
  993.   for (s = t = msg; *s && t - msg < max; ++s)
  994.     if (*s == BELL)
  995.       PutStr(BL);
  996.     else if ((unsigned char)*s >= ' ' && *s != 0177)
  997.       *t++ = *s;
  998.   *t = '\0';
  999.   if (t > msg)
  1000.     {
  1001.       if (t - msg >= d_status_buflen)
  1002.         {
  1003.           char *buf;
  1004.           if (d_status_lastmsg)
  1005.         buf = realloc(d_status_lastmsg, t - msg + 1);
  1006.       else
  1007.         buf = malloc(t - msg + 1);
  1008.       if (buf)
  1009.         {
  1010.               d_status_lastmsg = buf;
  1011.               d_status_buflen = t - msg + 1;
  1012.             }
  1013.         }
  1014.       if (t - msg < d_status_buflen)
  1015.         strcpy(d_status_lastmsg, msg);
  1016.       d_status = 1;
  1017.       d_status_len = t - msg;
  1018.       d_status_lastx = d_x;
  1019.       d_status_lasty = d_y;
  1020.       if (!use_hardstatus || !HS)
  1021.     {
  1022.       debug1("using STATLINE %d\n", STATLINE);
  1023.       GotoPos(0, STATLINE);
  1024.           SetAttrFont(A_SO, ASCII);
  1025.       InsertMode(0);
  1026.       AddStr(msg);
  1027.           d_x = -1;
  1028.     }
  1029.       else
  1030.     {
  1031.       debug("using HS\n");
  1032.           SetAttrFont(0, ASCII);
  1033.       InsertMode(0);
  1034.       CPutStr(TS, 0);
  1035.       AddStr(msg);
  1036.       PutStr(FS);
  1037.     }
  1038.       Flush();
  1039.       (void) time(&d_status_time);
  1040.     }
  1041. }
  1042.  
  1043. void
  1044. RemoveStatus()
  1045. {
  1046.   struct win *p;
  1047.  
  1048.   if (!display)
  1049.     return;
  1050.   if (!d_status)
  1051.     return;
  1052.   
  1053.   /*
  1054.    * UGLY HACK ALERT - this should NOT be in display.c
  1055.    * We need to find the window that caused an activity or bell
  1056.    * message, to reenable this function there.
  1057.    */
  1058.   for (p = windows; p; p = p->w_next)
  1059.     { 
  1060.       if (p->w_display != display)
  1061.     continue;
  1062.       if (p->w_monitor == MON_MSG)
  1063.     {
  1064.       debug1("RemoveStatus clearing monitor win %d\n", p->w_number);
  1065.       p->w_monitor = MON_DONE;
  1066.     }
  1067.       if (p->w_bell == BELL_MSG)
  1068.     {
  1069.       debug1("RemoveStatus clearing bell win %d\n", p->w_number);
  1070.       p->w_bell = BELL_DONE;
  1071.     }
  1072.     }
  1073.   d_status = 0;
  1074.   d_status_bell = 0;
  1075.   if (!use_hardstatus || !HS)
  1076.     {
  1077.       GotoPos(0, STATLINE);
  1078.       RefreshLine(STATLINE, 0, d_status_len - 1, 0);
  1079.       GotoPos(d_status_lastx, d_status_lasty);
  1080.     }
  1081.   else
  1082.     {
  1083.       SetAttrFont(0, ASCII);
  1084.       PutStr(DS);
  1085.     }
  1086.   SetCursor();
  1087. }
  1088.  
  1089. void
  1090. RefreshLine(y, from, to, isblank)
  1091. int y, from, to, isblank;
  1092. {
  1093.   ASSERT(display);
  1094.   debug2("RefreshLine %d %d", y, from);
  1095.   debug2(" %d %d\n", to, isblank);
  1096.   if (isblank == 0 && CE && to == d_width - 1)
  1097.     {
  1098.       GotoPos(from, y);
  1099.       PutStr(CE);
  1100.       isblank = 1;
  1101.     }
  1102.   RedisplayLine(y, from, to, isblank);
  1103. }
  1104.  
  1105. void
  1106. FixLP(x2, y2)
  1107. register int x2, y2;
  1108. {
  1109.   int oldattr = d_attr, oldfont = d_font;
  1110.  
  1111.   ASSERT(display);
  1112.   GotoPos(x2, y2);
  1113.   SetAttrFont(d_lp_attr, d_lp_font);
  1114.   PUTCHAR(d_lp_image);
  1115.   d_lp_missing = 0;
  1116.   SetAttrFont(oldattr, oldfont);
  1117. }
  1118.  
  1119. void
  1120. DisplayLine(os, oa, of, s, as, fs, y, from, to)
  1121. int from, to, y;
  1122. register char *os, *oa, *of, *s, *as, *fs;
  1123. {
  1124.   register int x;
  1125.   int last2flag = 0, delete_lp = 0;
  1126.  
  1127.   ASSERT(display);
  1128.   ASSERT(y >= 0 && y < d_height);
  1129.   ASSERT(from >= 0 && from < d_width);
  1130.   ASSERT(to >= 0 && to < d_width);
  1131.   if (!CLP && y == d_bot && to == d_width - 1)
  1132.     if (d_lp_missing
  1133.     || s[to] != os[to] || as[to] != oa[to] || of[to] != fs[to])
  1134.       {
  1135.     if ((IC || IM) && from < to)
  1136.       {
  1137.         to -= 2;
  1138.         last2flag = 1;
  1139.         d_lp_missing = 0;
  1140.       }
  1141.     else
  1142.       {
  1143.         to--;
  1144.         delete_lp = (CE || DC || CDC);
  1145.         d_lp_missing = (s[to] != ' ' || as[to] || fs[to]);
  1146.         d_lp_image = s[to];
  1147.         d_lp_attr = as[to];
  1148.         d_lp_font = fs[to];
  1149.       }
  1150.       }
  1151.     else
  1152.       to--;
  1153.   for (x = from; x <= to; ++x)
  1154.     {
  1155.       if (x || d_x != d_width || d_y != y - 1)
  1156.         {
  1157.       if (x < to || x != d_width - 1 || s[x + 1] == ' ')
  1158.         if (s[x] == os[x] && as[x] == oa[x] && of[x] == fs[x])
  1159.           continue;
  1160.       GotoPos(x, y);
  1161.         }
  1162.       SetAttr(as[x]);
  1163.       SetFont(fs[x]);
  1164.       PUTCHAR(s[x]);
  1165.     }
  1166.   if (to == d_width - 1 && y < d_height - 1 && s[to + 1] == ' ')
  1167.     GotoPos(0, y + 1);
  1168.   if (last2flag)
  1169.     {
  1170.       GotoPos(x, y);
  1171.       SetAttr(as[x + 1]);
  1172.       SetFont(fs[x + 1]);
  1173.       PUTCHAR(s[x + 1]);
  1174.       GotoPos(x, y);
  1175.       SetAttr(as[x]);
  1176.       SetFont(fs[x]);
  1177.       INSERTCHAR(s[x]);
  1178.     }
  1179.   else if (delete_lp)
  1180.     {
  1181.       if (DC)
  1182.     PutStr(DC);
  1183.       else if (CDC)
  1184.     CPutStr(CDC, 1);
  1185.       else if (CE)
  1186.     PutStr(CE);
  1187.     }
  1188. }
  1189.  
  1190. void
  1191. SetLastPos(x,y)
  1192. int x,y;
  1193. {
  1194.   ASSERT(display);
  1195.   d_x = x;
  1196.   d_y = y;
  1197. }
  1198.  
  1199. int
  1200. ResizeDisplay(wi, he)
  1201. int wi, he;
  1202. {
  1203.   ASSERT(display);
  1204.   debug2("ResizeDisplay: to (%d,%d).\n", wi, he);
  1205.   if (d_width == wi && d_height == he)
  1206.     {
  1207.       debug("ResizeDisplay: No change\n");
  1208.       return 0;
  1209.     }
  1210.   if (CWS)
  1211.     {
  1212.       debug("ResizeDisplay: using WS\n");
  1213.       PutStr(tgoto(CWS, wi, he));
  1214.       ChangeScreenSize(wi, he, 0);
  1215.       return 0;
  1216.     }
  1217.   else if (CZ0 && (wi == Z0width || wi == Z1width))
  1218.     {
  1219.       debug("ResizeDisplay: using Z0/Z1\n");
  1220.       PutStr(wi == Z0width ? CZ0 : CZ1);
  1221.       ChangeScreenSize(wi, d_height, 0);
  1222.       return (he == d_height) ? 0 : -1;
  1223.     }
  1224.   return -1;
  1225. }
  1226.  
  1227. void
  1228. ChangeScrollRegion(newtop, newbot)
  1229. int newtop, newbot;
  1230. {
  1231.   if (display == 0)
  1232.     return;
  1233.   if (CS == 0)
  1234.     {
  1235.       d_top = 0;
  1236.       d_bot = d_height - 1;
  1237.       return;
  1238.     }
  1239.   if (d_top == newtop && d_bot == newbot)
  1240.     return;
  1241.   debug2("ChangeScrollRegion: (%d - %d)\n", newtop, newbot);
  1242.   PutStr(tgoto(CS, newbot, newtop));
  1243.   d_top = newtop;
  1244.   d_bot = newbot;
  1245.   d_y = d_x = -1;        /* Just in case... */
  1246. }
  1247.  
  1248.  
  1249. /*
  1250.  *  Layer creation / removal
  1251.  */
  1252.  
  1253. int
  1254. InitOverlayPage(datasize, lf, block)
  1255. int datasize;
  1256. struct LayFuncs *lf;
  1257. int block;
  1258. {
  1259.   char *data;
  1260.   struct layer *newlay;
  1261.  
  1262.   RemoveStatus();
  1263.   debug3("Entering new layer  display %#x  d_fore %#x  oldlay %#x\n", 
  1264.        (unsigned int)display, (unsigned int)d_fore, (unsigned int)d_lay);
  1265.   if ((newlay = (struct layer *)malloc(sizeof(struct layer))) == 0)
  1266.     {
  1267.       Msg(0, "No memory for layer struct");
  1268.       return(-1);
  1269.     }
  1270.   data = 0;
  1271.   if (datasize)
  1272.     {
  1273.       if ((data = malloc(datasize)) == 0)
  1274.     {
  1275.       free(newlay);
  1276.       Msg(0, "No memory for layer data");
  1277.       return(-1);
  1278.     }
  1279.       bzero(data, datasize);
  1280.     }
  1281.   newlay->l_layfn = lf;
  1282.   newlay->l_block = block | d_lay->l_block;
  1283.   newlay->l_data = data;
  1284.   newlay->l_next = d_lay;
  1285.   if (d_fore)
  1286.     {
  1287.       d_fore->w_lay = newlay;    /* XXX: CHECK */
  1288.       d_fore->w_active = 0;    /* XXX: CHECK */
  1289.     }
  1290.   d_lay = newlay;
  1291.   d_layfn = newlay->l_layfn;
  1292.   Restore();
  1293.   return(0);
  1294. }
  1295.  
  1296. void
  1297. ExitOverlayPage()
  1298. {
  1299.   struct layer *oldlay;
  1300.  
  1301.   debug3("Exiting layer  display %#x  fore %#x  d_lay %#x\n", 
  1302.          (unsigned int)display, (unsigned int)d_fore, (unsigned int)d_lay);
  1303.   oldlay = d_lay;
  1304.   if (oldlay->l_data)
  1305.     free(oldlay->l_data);
  1306.   d_lay = oldlay->l_next;
  1307.   d_layfn = d_lay->l_layfn;
  1308.   free(oldlay);
  1309.   if (d_fore)
  1310.     d_fore->w_lay = d_lay;    /* XXX: Is this necessary ? */
  1311.   Restore();
  1312.   SetCursor();
  1313. }
  1314.  
  1315.  
  1316. /*
  1317.  *  Output buffering routines
  1318.  */
  1319.  
  1320. void
  1321. AddStr(str)
  1322. char *str;
  1323. {
  1324.   register char c;
  1325.  
  1326.   ASSERT(display);
  1327.   while ((c = *str++))
  1328.     AddChar(c);
  1329. }
  1330.  
  1331. void
  1332. AddStrn(str, n)
  1333. char *str;
  1334. int n;
  1335. {
  1336.   register char c;
  1337.  
  1338.   ASSERT(display);
  1339.   while ((c = *str++) && n-- > 0)
  1340.     AddChar(c);
  1341.   while (n-- > 0)
  1342.     AddChar(' ');
  1343. }
  1344.  
  1345. void
  1346. Flush()
  1347. {
  1348.   register int l;
  1349.   register char *p;
  1350.  
  1351.   ASSERT(display);
  1352.   l = d_obufp - d_obuf;
  1353.   debug1("Flush(): %d\n", l);
  1354.   ASSERT(l + d_obuffree == d_obuflen);
  1355.   if (l == 0)
  1356.     return;
  1357.   if (d_userfd < 0)
  1358.     {
  1359.       d_obuffree += l;
  1360.       d_obufp = d_obuf;
  1361.       return;
  1362.     }
  1363.   p = d_obuf;
  1364.   if (fcntl(d_userfd, F_SETFL, 0))
  1365.     debug1("Warning: DELAY fcntl failed: %d\n", errno);
  1366.   while (l)
  1367.     {
  1368.       register int wr;
  1369.       wr = write(d_userfd, p, l);
  1370.       if (wr <= 0) 
  1371.     {
  1372.       if (errno == EINTR) 
  1373.         continue;
  1374.       debug1("Writing to display: %d\n", errno);
  1375.       wr = l;
  1376.     }
  1377.       d_obuffree += wr;
  1378.       p += wr;
  1379.       l -= wr;
  1380.     }
  1381.   d_obuffree += l;
  1382.   d_obufp = d_obuf;
  1383.   if (fcntl(d_userfd, F_SETFL, FNDELAY))
  1384.     debug1("Warning: NDELAY fcntl failed: %d\n", errno);
  1385. }
  1386.  
  1387. void
  1388. freetty()
  1389. {
  1390.   if (d_userfd >= 0)
  1391.     close(d_userfd);
  1392.   debug1("did freetty %d\n", d_userfd);
  1393.   d_userfd = -1;
  1394.   d_obufp = 0;
  1395.   d_obuffree = 0;
  1396.   if (d_obuf)
  1397.     free(d_obuf);
  1398.   d_obuf = 0;
  1399.   d_obuflen = 0;
  1400. }
  1401.  
  1402. /*
  1403.  *  Asynchronous output routines by
  1404.  *  Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
  1405.  */
  1406.  
  1407. void
  1408. Resize_obuf()
  1409. {
  1410.   register int ind;
  1411.  
  1412.   ASSERT(display);
  1413.   if (d_obuflen && d_obuf)
  1414.     {
  1415.       ind  = d_obufp - d_obuf;
  1416.       d_obuflen += GRAIN;
  1417.       d_obuffree += GRAIN;
  1418.       d_obuf = realloc(d_obuf, d_obuflen);
  1419.     }
  1420.   else
  1421.     {
  1422.       ind  = 0;
  1423.       d_obuflen = GRAIN;
  1424.       d_obuffree = GRAIN;
  1425.       d_obuf = malloc(d_obuflen);
  1426.     }
  1427.   if (!d_obuf)
  1428.     Panic(0, "Out of memory");
  1429.   d_obufp = d_obuf + ind;
  1430.   debug1("ResizeObuf: resized to %d\n", d_obuflen);
  1431. }
  1432.  
  1433. #ifdef AUTO_NUKE
  1434. void
  1435. NukePending()
  1436. {/* Nuke pending output in current display, clear screen */
  1437.   register int len;
  1438.   int oldfont = d_font, oldattr = d_attr, oldtop = d_top, oldbot = d_bot;
  1439.   int oldkeypad = d_keypad, oldcursorkeys = d_cursorkeys;
  1440.  
  1441.   len = d_obufp - d_obuf;
  1442.   debug1("NukePending: nuking %d chars\n", len);
  1443.   
  1444.   /* Throw away any output that we can... */
  1445. # ifdef POSIX
  1446.   tcflush(d_userfd, TCOFLUSH);
  1447. # else
  1448. #  ifdef TCFLSH
  1449.   (void) ioctl(d_userfd, TCFLSH, (char *) 1);
  1450. #  endif
  1451. # endif
  1452.  
  1453.   d_obufp = d_obuf;
  1454.   d_obuffree += len;
  1455.   d_top = d_bot = -1;
  1456.   PutStr(TI);
  1457.   PutStr(IS);
  1458.   /* Turn off all attributes. (Tim MacKenzie) */
  1459.   if (ME)
  1460.     PutStr(ME);
  1461.   else
  1462.     {
  1463.       PutStr(SE);
  1464.       PutStr(UE);
  1465.     }
  1466.   /* Check for toggle */
  1467.   if (IM && strcmp(IM, EI))
  1468.     PutStr(EI);
  1469.   d_insert = 0;
  1470.   /* Check for toggle */
  1471.   if (KS && strcmp(KS, KE))
  1472.     PutStr(KE);
  1473.   d_keypad = 0;
  1474.   if (CCS && strcmp(CCS, CCE))
  1475.     PutStr(CCE);
  1476.   d_cursorkeys = 0;
  1477.   PutStr(CE0);
  1478.   d_font = ASCII;
  1479.   d_attr = 0;
  1480.   ChangeScrollRegion(oldtop, oldbot);
  1481.   SetAttrFont(oldattr, oldfont);
  1482.   KeypadMode(oldkeypad);
  1483.   CursorkeysMode(oldcursorkeys);
  1484.   if (CWS)
  1485.     {
  1486.       debug("ResizeDisplay: using WS\n");
  1487.       PutStr(tgoto(CWS, d_width, d_height));
  1488.     }
  1489.   else if (CZ0 && (d_width == Z0width || d_width == Z1width))
  1490.     {
  1491.       debug("ResizeDisplay: using Z0/Z1\n");
  1492.       PutStr(d_width == Z0width ? CZ0 : CZ1);
  1493.     }
  1494. }
  1495. #endif /* AUTO_NUKE */
  1496.