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