home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / mint / mw2 / mwsubr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-03  |  33.1 KB  |  1,372 lines

  1. /* subroutines for multi-window terminal emulation
  2.  */
  3.  
  4. #ifdef __GNUC__
  5. #  include <gemfast.h>
  6. #  include <aesbind.h>
  7. #  include <vdibind.h>
  8. #else
  9. #  include <obdefs.h>
  10. #  include <gemdefs.h>
  11. #endif
  12. #include <osbind.h>
  13. #include <stdio.h>
  14. #include "mw.h"
  15. #include "mwdefs.h"
  16.  
  17. extern int screen_handle;
  18.  
  19. /* variables used by various routines
  20.  */
  21.  
  22. extern  long dummy;            /* dummy return variable */
  23. extern    int sdummy;            /* short-sized dummy */
  24.  
  25. extern    int    scr_x, scr_y;        /* size of the screen */
  26. extern    int    scr_w, scr_h;
  27. extern    int    fast;
  28. /* this makes more updates happen in "scrolled" mode with delayed updates */
  29. extern    int    jerky_updates;
  30. extern    int    mouseflicker;        /* for knowing when to turn it on */
  31. extern    int    audibell;        /* What happens on BEL? */
  32. extern    int    visibell;
  33.  
  34. extern    FNT    *curfont;        /* current font */
  35. extern    WIN_MFDB screen_mf;        /* screen descriptor */
  36. extern    int    mouse;            /* for mouse on/off */
  37.  
  38. extern  struct wi_str *wlist;
  39.  
  40. extern int ncolors;            /* used by ESCb and ESCc */
  41.  
  42. #if DEBUG
  43. extern char dbstr[];
  44. #define DB(x) put_str(x)
  45. #define DB1(x,y) sprintf(dbstr,x,y), put_str(dbstr)
  46. #define DB2(x,y,z) sprintf(dbstr,x,y,z), put_str(dbstr)
  47. #define DB4(s,a,b,c,d) sprintf(dbstr,s,a,b,c,d), put_str(dbstr)
  48. #define DB6(s,a,b,c,d,e,f) sprintf(dbstr,s,a,b,c,d,e,f), put_str(dbstr)
  49. #else
  50. #define DB(x)
  51. #define DB1(x,y)
  52. #define DB2(x,y,z)
  53. #define DB4(s,a,b,c,d)
  54. #define DB6(s,a,b,c,d,e,f)
  55. #endif
  56.  
  57. /* the program code... */
  58.  
  59. char *getmem(size)
  60. register long size;
  61. {
  62.   char *got;
  63.  
  64.   /* this relies on malloc taking size_t, and size_t being long, */
  65.   /* or else not compiling with -mshort */
  66.   got = (char *) malloc(size);
  67.   if (got == NULL) {
  68.     form_alert(1, "[1][Out of memory][ Ok ]");
  69.   }
  70.   else {
  71.     bzero(got, size);
  72.   }
  73.   return got;
  74. }
  75.  
  76. /*
  77.  * w_open opens a window with the supplied name.  The new window is
  78.  * top, ergo wlist.  Puts up an alert & returns -1 on errors.
  79.  */
  80.  
  81. int
  82. w_open(name, xpos, ypos, xsiz, ysiz, sliders, titles, usefont)
  83. char *name;
  84. int xpos, ypos, xsiz, ysiz;
  85. int sliders, titles;    /* nonzero to get that thing */
  86. FNT *usefont;        /* ptr to font to use */
  87. {
  88.   register struct wi_str *wp;
  89.   int wdes;
  90.   int wtyp;
  91.   int tmp_w, tmp_h;
  92.  
  93.   wtyp = (sliders ? WI_WITHSLD : 0) | (titles ? WI_WITHTITLE : 0);
  94.   if (ypos < scr_y) ypos = scr_y;
  95.   if (xpos < scr_x) xpos = scr_x;
  96.       
  97.   wind_calc(0, wtyp, 0, 0, usefont->inc_x*xsiz+2*X0,
  98.     usefont->inc_y*ysiz+2*Y0, &sdummy, &sdummy, &tmp_w, &tmp_h);
  99.  
  100.   if (tmp_w>scr_w)
  101.     tmp_w = scr_w;    /* full size <= screen size */
  102.  
  103.   if (tmp_h>scr_h)
  104.     tmp_h = scr_h;
  105.  
  106.   wp = (struct wi_str *)getmem(sizeof(struct wi_str));
  107.   if (wp == NULL) {
  108.       return -1;
  109.   }
  110.  
  111.   wp->wi_mf.wpix = 2*X0 + xsiz*usefont->inc_x;
  112.   wp->wi_mf.hpix = 2*Y0 + ysiz*usefont->inc_y;
  113.   wp->wi_mf.wwords = (wp->wi_mf.wpix>>4) +1;
  114.   wp->wi_mf.planes = 1;
  115.   wp->font = usefont;
  116.   wp->fgbg[1] = 0;    /* foreground color for vrt_copyfm */
  117.   wp->fgbg[0] = 1;    /* background color for vrt_copyfm */
  118.  
  119.   /* allocate a screen image for this window before wind_create */
  120.   wp->wi_mf.ptr = (short *)getmem(
  121.     ((long)wp->wi_mf.hpix + wp->font->inc_y*MAXSCROLLED) * 
  122.         wp->wi_mf.wwords*2);
  123.  
  124.   if (wp->wi_mf.ptr == NULL) {
  125.       free(wp);
  126.     return -1;
  127.   }
  128.  
  129.   wdes = wind_create(wtyp, scr_x, scr_y, tmp_w, tmp_h);
  130.   if (wdes < 0) {
  131.     form_alert(1, "[1][Sorry, GEM has|no more windows|for us...][Ok]");
  132.     free(wp->wi_mf.ptr);
  133.     free(wp);
  134.     return -1;
  135.   }
  136.  
  137.   /* install at head of wlist list (which is sorted by window depth) */
  138.   if (wlist == NULL) {
  139.     wp->next = wp->prev = wp;
  140.   }
  141.   else {
  142.     wp->next = wlist;
  143.     wp->prev = wlist->prev;
  144.     wlist->prev->next = wp;
  145.     wlist->prev = wp;
  146.   }
  147.   wlist = wp;
  148.  
  149.   wp->sliders = sliders;
  150.   wp->titles = titles;
  151.   wp->aes_handle = wdes;
  152.   wp->wi_w = X0*2 + usefont->inc_x*xsiz;
  153.   wp->wi_h = Y0*2 + usefont->inc_y*ysiz;
  154.   wp->wi_style = wtyp;
  155.   wp->wi_mainstyle = wtyp;
  156.  
  157.   w_rename(wp, name);
  158.  
  159.   if (!fast)
  160.     graf_growbox(0, 0, 20, 10, xpos, ypos, tmp_w, tmp_h);
  161.   wind_open(wdes, xpos, ypos, tmp_w, tmp_h);
  162.   wind_get(wdes, WF_WORKXYWH, &wp->x, &wp->y, &wp->w, &wp->h);
  163.  
  164.   wp->fulled = 0;
  165.   wp->x_off = 0;
  166.   wp->y_off = 0;
  167.   wp->px_off = 0;
  168.   wp->py_off = 0;
  169.   wp->m_off = wp->x & 15;   /* when is this used? */
  170.   wp->cur_x = X0;
  171.   wp->cur_y = Y0;
  172.   wp->top_y = Y0;
  173.   wp->x_chrs = xsiz;
  174.   wp->y_chrs = ysiz;
  175.  
  176.   setvslide(wp);
  177.   sethslide(wp);
  178.  
  179.   return 0;
  180. }
  181.  
  182. /*
  183.  * w_closei removes a window but does not release its storage.  This is used
  184.  * if the window contents must be saved for later use.
  185.  */
  186. void
  187. w_closei(wp)
  188. struct wi_str *wp;
  189. {
  190.   int xx, yy, ww, hh;
  191.   int wdes = wp->aes_handle;
  192.  
  193.   wind_get(wdes, WF_CURRXYWH, &xx, &yy, &ww, &hh);
  194.   wind_close(wdes);
  195.   if (!fast)
  196.     graf_shrinkbox(0, 0, 20, 10, xx, yy, ww, hh);
  197.   wind_delete(wdes);
  198. }
  199.  
  200. /*
  201.  * w_close removes a window.
  202.  */
  203. void
  204. w_close(wp)
  205. struct wi_str *wp;
  206. {
  207.   /* unlink me */
  208.   wp->prev->next = wp->next;
  209.   wp->next->prev = wp->prev;
  210.   if (wp->next == wp) wlist = NULL;    /* singleton list */
  211.   else if (wlist == wp) wlist = wp->next;
  212.  
  213.   w_closei(wp);
  214.   free(wp->wi_mf.ptr);
  215.   free(wp);
  216. }
  217.  
  218. /* w_resize resizes an existing window.  Also lets you pass in the
  219.  * sliders & titles arguments for the newly-sized window.
  220.  *
  221.  * This used to relocate the window; now it copies the xy.
  222.  * This used to change the font in the window; now it doesn't unless
  223.  * chfont == 1.
  224.  */
  225. int
  226. w_resize(wp1, xsiz, ysiz, sliders, titles, chfont)
  227. struct wi_str *wp1;
  228. int xsiz, ysiz;
  229. int sliders, titles;
  230. int chfont;            /* flag: when 0 don't change font */
  231. {
  232.   struct wi_str *wp2;
  233.   static int c[8];
  234.   int tmp_x, tmp_y, tmp_w, tmp_h, wtyp;
  235.   int curstate;
  236.   int retcode;
  237.  
  238.   curstate = wp1->curstate;
  239.   if (curstate) {
  240.     w_flash(wp1,0);
  241.   }
  242.  
  243.   w_closei(wp1);        /* close it (closes AES window) */
  244.  
  245.     /*
  246.      * what's happening here is that the overlap of screen images between
  247.      * the old & new sizes gets copied into the new window. This is done by
  248.      * deleting the old window, creating a new one of the new size, and
  249.      * copying the appropriate rectangle of screen image over.
  250.      */
  251.  
  252.   /* unlink me */
  253.   wp1->prev->next = wp1->next;
  254.   wp1->next->prev = wp1->prev;
  255.   if (wp1->next == wp1) wlist = NULL;
  256.   else if (wlist == wp1) wlist = wp1->next;
  257.  
  258.   wtyp = (sliders ? WI_WITHSLD : 0) | (titles ? WI_WITHTITLE : 0);
  259.   wind_calc(0,wtyp,wp1->x,wp1->y,wp1->w,wp1->h,
  260.       &tmp_x, &tmp_y, &tmp_w, &tmp_h);
  261.       
  262.   /* open this window with the same workxy as the previous */
  263.   if (w_open(wp1->name, tmp_x, tmp_y, xsiz, ysiz, 
  264.     sliders, titles, (chfont ? curfont : wp1->font))) {
  265.         /* error opening the new copy of the window */
  266.         retcode = -1;
  267.         goto freeold;
  268.   }
  269.  
  270.   wp2 = wlist;
  271.   c[0] = wp1->m_off;
  272.   c[1] = wp1->top_y + max(0, wp1->wi_mf.hpix - wp2->wi_mf.hpix);
  273.   c[2] = c[0] + min(wp1->wi_mf.wpix, wp2->wi_mf.wpix);
  274.   c[3] = c[1] + min(wp1->wi_mf.hpix, wp2->wi_mf.hpix);
  275.   c[4] = wp2->m_off;
  276.   c[5] = wp2->top_y;
  277.   c[6] = c[4] + min(wp1->wi_mf.wpix, wp2->wi_mf.wpix);
  278.   c[7] = c[5] + min(wp1->wi_mf.hpix, wp2->wi_mf.hpix);
  279.  
  280.   /* copy screen */
  281.   vro_cpyfm(screen_handle, FM_COPY, c, &wp1->wi_mf, &wp2->wi_mf);
  282.   /* copy parameters */
  283.   wp2->fgbg[0] = wp1->fgbg[0];
  284.   wp2->fgbg[1] = wp1->fgbg[1];
  285.   wp2->insmode = wp1->insmode;
  286.  
  287.   wp2->fd = wp1->fd;
  288.   wp2->pid = wp1->pid;
  289.  
  290.   if (wtyp != wp1->wi_mainstyle) {
  291.     /* you're changing the style... copy mainstyle from the original */
  292.     wp2->wi_mainstyle = wp1->wi_mainstyle;
  293.   }
  294.  
  295.   /*
  296.    * if font changed, put cursor at bottom left.  Else put it at old X
  297.    * offset (or right edge if narrower than that), and I can't figure out
  298.    * the calculation for Y.
  299.    */
  300.   if (wp2->font != wp1->font) {
  301.     wp2->cur_x = X0;
  302.     wp2->cur_y = (wp2->y_chrs - 1) * wp2->font->inc_y + Y0;
  303.   }
  304.   else {
  305.     wp2->cur_x = (wp2->x_chrs - 1) * wp2->font->inc_x + X0;
  306.     if (wp1->cur_x < wp2->cur_x)
  307.       wp2->cur_x = wp1->cur_x;
  308.     wp2->cur_y = max(0, wp1->cur_y - c[1]) + Y0;
  309.   }
  310.   wp2->state = wp1->state;
  311.   strcpy(wp2->nuname,wp1->nuname);
  312.  
  313.   wp2->nuptr = wp1->nuptr;
  314.  
  315.   w_flash(wp2,curstate);
  316.   retcode = 0;
  317.  
  318. freeold:
  319.   free(wp1->wi_mf.ptr);
  320.   free(wp1);
  321.   return retcode;    /* old window is GONE if this is -1 */
  322. }
  323.  
  324. /* w_rename changes the title bar of a window
  325.  */
  326. void
  327. w_rename(wp, name)
  328. struct wi_str *wp;
  329. char *name;
  330. {
  331.   if (name)
  332.     strcpy(wp->name, name);
  333.   if (wp->wi_style & NAME) {
  334.     wind_set(wp->aes_handle, WF_NAME, wp->name, 0, 0);
  335.   }
  336. }
  337.  
  338. /* w_redraw redraws part of the screen from window contents.
  339.  * The coordinates are screen relative.
  340.  */
  341. void
  342. w_redraw(wp, logic, xx, yy, ww, hh)
  343. struct wi_str *wp;
  344. int logic,xx,yy,ww,hh;
  345. {
  346.   int c[8];
  347.   GRECT t1, t2;
  348.   int wdes = wp->aes_handle;
  349.  
  350.   /* turn vro_cpyfm logic ops into vrt_cpyfm ones */
  351.   if (logic == FM_INVERT) logic = 3;
  352.   else logic = 1;
  353.  
  354.   if (xx+ww > scr_w)
  355.     ww = scr_w - xx;
  356.   if (yy+hh > scr_h+scr_y)
  357.     hh = scr_h+scr_y - yy;
  358.   t2.g_x = xx; t2.g_y = yy;
  359.   t2.g_w = ww; t2.g_h = hh;
  360.   t1.g_x = wp->x; t1.g_y = wp->y;
  361.   t1.g_w = wp->w; t1.g_h = wp->h;
  362.   if (!rc_intersect(&t2, &t1)) {
  363.     return;    /* nothing to do... */
  364.   }
  365.   *(long *)0x003ffffc = 1;
  366.   wind_update(TRUE);
  367.   *(long *)0x003ffffc = 2;
  368.   wind_get(wdes, WF_FIRSTXYWH, &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h);
  369.   while (t1.g_w && t1.g_h) {
  370.     if (rc_intersect(&t2, &t1)) {
  371.       if (mouse) {
  372.     /* we have to do graphics, so switch the mouse off.
  373.      * mouse will be switched on again in main loop.
  374.      * this is ugly, but it improves speed a bit...
  375.      * (If mouseflicker is ON, we'll turn it on again below)
  376.      */
  377.     mouse = 0;
  378.     graf_mouse(M_OFF, NULL);
  379.       }
  380.       c[0] = t1.g_x - wp->x + wp->x_off + wp->m_off;
  381.       c[1] = t1.g_y - wp->y + wp->y_off + wp->top_y - Y0;
  382.       c[2] = c[0] + t1.g_w - 1;
  383.       c[3] = c[1] + t1.g_h - 1;
  384.       c[4] = t1.g_x;
  385.       c[5] = t1.g_y;
  386.       c[6] = c[4] + t1.g_w - 1;
  387.       c[7] = c[5] + t1.g_h - 1;
  388.       vrt_cpyfm(screen_handle, logic, c,
  389.               &wp->wi_mf, &screen_mf, wp->fgbg);
  390.     }
  391.     *(long *)0x003ffffc = 3;
  392.     wind_get(wdes, WF_NEXTXYWH, &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h);
  393.   }
  394.   *(long *)0x003ffffc = 4;
  395.   wind_update(FALSE);
  396.   /* mouse stays hidden -- we'll make it visible next time it moves */
  397.   /* except if mouseflicker is on, in which case we'll do it NOW */
  398.   if (!mouse && mouseflicker) {
  399.     mouse = 1;
  400.     graf_mouse(M_ON,NULL);
  401.   }
  402. }
  403.  
  404. /* w_update copies a portion of the window to the screen.  Coordinates
  405.  * are window-relative
  406.  */
  407. void
  408. w_update(wp, logic, xx, yy, ww, hh)
  409. struct wi_str *wp;
  410. int logic, xx,yy,ww,hh;
  411. {
  412.   w_redraw(wp, logic, xx + wp->x - wp->x_off, 
  413.           yy + wp->y - wp->y_off - wp->top_y + Y0, ww, hh);
  414. }
  415.  
  416. /* w_move sets the window's idea of its own position on the screen
  417.  */
  418.  
  419. void
  420. w_move(wp, xx, yy, ww, hh)
  421. struct wi_str *wp;
  422. int xx, yy, ww, hh;
  423. {
  424.   int wdes = wp->aes_handle;
  425.   int flag = 0;
  426.   int m_w, m_h;
  427.   int x1, x2;
  428.   int tmp;
  429.   int c[8];
  430.   int inc_x, inc_y;
  431.  
  432.   wind_calc(1, wp->wi_style, xx, yy, ww, hh, &sdummy, &sdummy, &m_w, &m_h);
  433.   if (tmp = (m_w-2*X0)%wp->font->inc_x) {
  434.     ww -= tmp;
  435.     m_w -= tmp;
  436.   }
  437.   if (tmp = (m_h-2*Y0)%wp->font->inc_y) {
  438.     hh -= tmp;
  439.     m_h -= tmp;
  440.   }
  441.   if (m_w>wp->wi_w) ww = ww-(m_w-wp->wi_w);
  442.   if (m_h>wp->wi_h) hh = hh-(m_h-wp->wi_h);
  443.   wind_set(wdes, WF_CURRXYWH, xx, yy, ww, hh);
  444.   wind_get(wdes, WF_WORKXYWH, &wp->x, &wp->y, &wp->w, &wp->h);
  445.   if (wp->x_off+wp->w > wp->wi_w) {
  446.     inc_x = wp->font->inc_x;
  447.     flag = 1;
  448.     wp->x_off = (wp->wi_w - wp->w)/inc_x*inc_x;
  449.   }
  450.   if (wp->y_off+wp->h > wp->wi_h) {
  451.     inc_y = wp->font->inc_y;
  452.     flag = 1;
  453.     wp->y_off = (wp->wi_h - wp->h)/inc_y*inc_y;
  454.   }
  455.   x1 = wp->m_off;
  456.   x2 = (wp->x - wp->x_off) & 15;
  457.   if (x1 != x2) {
  458.     c[0] = x1;
  459.     c[1] = wp->top_y;    /* displayed part of memory form starts here */
  460.     c[2] = x1 + wp->wi_w - 1;
  461.     c[3] = wp->wi_h - 1 + c[1];
  462.     c[4] = x2;
  463.     c[5] = c[1];
  464.     c[6] = x2 + wp->wi_w - 1;
  465.     c[7] = c[3];
  466.     vro_cpyfm(screen_handle, FM_COPY, c, &wp->wi_mf, &wp->wi_mf);
  467.     wp->m_off = x2;
  468.   }
  469.   if (flag)
  470.     w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h);
  471.   setvslide(wp);
  472.   sethslide(wp);
  473. }
  474.  
  475. /*
  476.  * w_top makes win the top window.
  477.  */
  478.  
  479. void
  480. w_top(wp)
  481. struct wi_str *wp;
  482. {
  483.   wind_set(wp->aes_handle, WF_TOP, 0, 0, 0, 0);
  484.  
  485.   if (wlist == wp) return;    /* already top of list */
  486.  
  487.   /* unlink from its current place */
  488.   wp->next->prev = wp->prev;
  489.   wp->prev->next = wp->next;
  490.  
  491.   /* link into top */
  492.   wp->next = wlist;
  493.   wp->prev = wlist->prev;
  494.   wlist->prev->next = wp;
  495.   wlist->prev = wp;
  496.   wlist = wp;
  497. }
  498.  
  499. /*
  500.  * w_bottom finds the bottom window and puts it on top
  501.  */
  502.  
  503. void
  504. w_bottom()
  505. {
  506.   struct wi_str *wp;
  507.   
  508.   if (!wlist || wlist->next == wlist) return;
  509.   for (wp = wlist->next; wp->next != wlist; wp = wp->next) /* do nothing */ ;
  510.   w_top(wp);
  511. }
  512.  
  513. /*
  514.  * w_hide puts the top window on the bottom.
  515.  * (a.k.a. "bury")
  516.  */
  517.  
  518. void
  519. w_hide()
  520. {
  521.   struct wi_str *wp, *oldtop;
  522.  
  523.   /* top all the windows, in order, from back to front, except the first. */
  524.   if (!wlist || wlist->next == wlist) return;    /* empty or singleton list */
  525.   oldtop = wlist;        /* window NOT to top */
  526.   for (wp = wlist->prev; wp != oldtop; wp = wp->prev)
  527.     wind_set(wp->aes_handle,WF_TOP, 0,0,0,0);
  528.  
  529.   /* move the top element from wlist to the end of wlist (easy!) */
  530.   wlist = wlist->next;
  531. }
  532.  
  533. #define TINYX 80
  534. #define TINYY 70
  535. /*
  536.  * w_shrink saves current size and location and shrinks to standard tiny size.
  537.  * The second from the top non-shrunk window is placed on top.
  538.  */
  539.  
  540. void
  541. w_shrink(wp)
  542. struct wi_str *wp;
  543. {
  544.   int wdes = wp->aes_handle;
  545.   int curx, cury, curw, curh;
  546.   static int slotcount;
  547.  
  548.   /*
  549.    * Don't shrink a window that is currently shrunk
  550.    */
  551.   wind_get(wdes, WF_CURRXYWH, &curx, &cury, &curw, &curh);
  552.   if (curw <= TINYX && cury <= TINYY)
  553.     return;
  554.  
  555.   if (wp->slotno == 0) wp->slotno = ++slotcount;
  556.  
  557.   /*
  558.    * By setting wp->fulled to one and the "previous" size to tiny,
  559.    * we're saying that the current size is the "full" size, and we
  560.    * want to "toggle to" the tiny size.
  561.    */
  562.   wp->fulled = 1;
  563.   wp->px = scr_x + (scr_w - TINYX + 2);
  564.   wp->py = scr_y + ((wp->slotno-1) * (TINYY + 2));
  565.   wp->pw = TINYX;
  566.   wp->ph = TINYY;
  567.  
  568.   /* ensure at least 10 dots of title bar on screen */
  569.   if (wp->py + 10 > scr_y + scr_h) {
  570.     wp->py = wp->py - scr_h + 10;
  571.     wp->px = scr_x + scr_w - TINYY * 2;
  572.   }
  573.   w_full(wp);
  574.  
  575.   /* now top the topmost window which isn't already tiny */
  576.  
  577.   wp = wlist;
  578.   do {
  579.     wdes = wp->aes_handle;
  580.     wind_get(wdes, WF_CURRXYWH, &curx, &cury, &curw, &curh);
  581.     if (curw > TINYX || curh > TINYY) {
  582.     w_full(wp);
  583.     w_top(wp);
  584.     return;
  585.     }
  586.     wp = wp->next;
  587.   } while (wp != wlist);
  588.  
  589.   /* no windows are not shrunk; just leave 'em */
  590. }
  591.  
  592. /* w_full toggles size and location between the current size and
  593.  * the "previous" size.
  594.  */
  595.  
  596. void
  597. w_full(wp)
  598. struct wi_str *wp;
  599. {
  600.   int x1, y1, w1, h1;
  601.   int x2, y2, w2, h2;
  602.   int full;
  603.   int wdes = wp->aes_handle;
  604.  
  605.   full = wp->fulled;
  606.  
  607.   /* if already full, set to "previous" size, else to full size */
  608.   if (full) {
  609.     x1 = wp->px;
  610.     y1 = wp->py;
  611.     w1 = wp->pw;
  612.     h1 = wp->ph;
  613.   }
  614.   else
  615.     wind_get(wdes, WF_FULLXYWH, &x1, &y1, &w1, &h1);
  616.  
  617.   wind_get(wdes, WF_CURRXYWH, &x2, &y2, &w2, &h2);
  618.   wp->px = x2;
  619.   wp->py = y2;
  620.   wp->pw = w2;
  621.   wp->ph = h2;
  622.   if (!fast) {
  623.     if (w2>=w1)
  624.       graf_growbox(x1, y1, w1, h1, x2, y2, w2, h2);
  625.     else
  626.       graf_shrinkbox(x1, y1, w1, h1, x2, y2, w2, h2);
  627.   }
  628.  
  629.   x2 = wp->x_off;
  630.   y2 = wp->y_off;
  631.   wp->x_off = wp->px_off;
  632.   wp->y_off = wp->py_off;
  633.   wp->px_off = x2;
  634.   wp->py_off = y2;
  635.  
  636.   w_move(wp, x1, y1, w1, h1);
  637.   w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h);
  638.   wp->fulled = 1;
  639. }
  640.  
  641. void
  642. w_arrow(wp, arrow)
  643. struct wi_str *wp;
  644. int arrow;
  645. {
  646.   int inc_x = wp->font->inc_x;
  647.   int inc_y = wp->font->inc_y;
  648.  
  649.   switch (arrow) {
  650.   case 0:    /* page up */
  651.     wp->y_off -= wp->h/inc_y*inc_y;
  652.     goto y_upd;
  653.  
  654.   case 1:    /* page down */
  655.     wp->y_off += wp->h/inc_y*inc_y;
  656.     goto y_upd;
  657.  
  658.   case 2:    /* row up */
  659.     wp->y_off -= inc_y;
  660.     goto y_upd;
  661.  
  662.   case 3:    /* row down */
  663.     wp->y_off += inc_y;
  664.     goto y_upd;
  665.  
  666.   case 4:    /* page left */
  667.     wp->x_off -= wp->w/inc_x*inc_x;
  668.     goto x_upd;
  669.  
  670.   case 5:    /* page right */
  671.     wp->x_off += wp->w/inc_x*inc_x;
  672.     goto x_upd;
  673.  
  674.   case 6:    /* column left */
  675.     wp->x_off -= inc_x;
  676.     goto x_upd;
  677.  
  678.   case 7:    /* column right */
  679.     wp->x_off += inc_x;
  680.     goto x_upd;
  681.   }
  682.  
  683. x_upd:
  684.   if (wp->x_off<0) wp->x_off = 0; else
  685.   if (wp->x_off+wp->w > wp->wi_w) wp->x_off = (wp->wi_w - wp->w)/inc_x*inc_x;
  686.   sethslide(wp);
  687.   goto upd;
  688.  
  689. y_upd:
  690.   if (wp->y_off<0) wp->y_off = 0; else
  691.   if (wp->y_off+wp->h > wp->wi_h) wp->y_off = (wp->wi_h - wp->h)/inc_y*inc_y;
  692.   setvslide(wp);
  693.   
  694. upd:
  695.   w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h);
  696. }
  697.  
  698. void
  699. w_slide(wp, hor, val)
  700. struct wi_str *wp;
  701. int hor, val;
  702. {
  703.   int tmp;
  704.  
  705.   if (hor) {
  706.     tmp = wp->font->inc_x;
  707.     wp->x_off = ((long)val*(wp->wi_w-wp->w)/1000)/tmp*tmp;
  708.     sethslide(wp);
  709.   }
  710.   else {
  711.     tmp = wp->font->inc_y;
  712.     wp->y_off = ((long)val*(wp->wi_h-wp->h)/1000)/tmp*tmp;
  713.     setvslide(wp);
  714.   }
  715.   w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h);
  716. }
  717.  
  718. void
  719. sethslide(wp)
  720. struct wi_str *wp;
  721. {
  722.   int tmp;
  723.   int wdes = wp->aes_handle;
  724.  
  725.   if (wp->wi_style & HSLIDE) {
  726.     if (wp->wi_w == wp->w) tmp = 0;
  727.     else tmp = (long)1000*wp->x_off/(wp->wi_w-wp->w);
  728.     if (tmp != wp->hspos) {
  729.     wind_set(wdes, WF_HSLIDE, tmp, 0, 0, 0);
  730.     wp->hspos = tmp;
  731.     }
  732.  
  733.     tmp = (long)1000*wp->w/wp->wi_w;
  734.     if (tmp != wp->hssiz) {
  735.     wind_set(wdes, WF_HSLSIZE, tmp, 0, 0, 0);
  736.     wp->hssiz = tmp;
  737.     }
  738.   }
  739. }
  740.  
  741. void
  742. setvslide(wp)
  743. struct wi_str *wp;
  744. {
  745.   int tmp;
  746.   int wdes = wp->aes_handle;
  747.  
  748.   if (wp->wi_style & VSLIDE) {
  749.     if (wp->wi_h == wp->h) tmp = 0;
  750.     else tmp = (long)1000*wp->y_off/(wp->wi_h-wp->h);
  751.     if (tmp != wp->vspos) {
  752.     wind_set(wdes, WF_VSLIDE, tmp, 0, 0, 0);
  753.     wp->vspos = tmp;
  754.     }
  755.  
  756.     tmp = (long)1000*wp->h/wp->wi_h;
  757.     if (tmp != wp->vssiz) {
  758.     wind_set(wdes, WF_VSLSIZE, tmp, 0, 0, 0);
  759.     wp->vssiz = tmp;
  760.     }
  761.   }
  762. }
  763.  
  764. /*
  765.  * flash the cursor in a window; if it's not the last one we flashed,
  766.  * un_flash that one
  767.  */
  768. void
  769. w_flash(wp, state)
  770. struct wi_str *wp;
  771. int state;
  772. {
  773.   static struct wi_str *wp_last = NULL;
  774.   int wdes;
  775.   int t[8];
  776.  
  777.   wdes = wp->aes_handle;
  778.   if (wp_last && wp != wp_last) w_flash(wp_last, 1);
  779.   wp_last = wp;
  780.   if (wp->curstate == state) return;
  781.   if (state == 2)
  782.     wp->curstate = !wp->curstate;
  783.   else
  784.     wp->curstate = state;
  785.   t[0] = t[4] = wp->cur_x + wp->m_off;
  786.   t[1] = t[5] = wp->cur_y;
  787.   t[2] = t[6] = t[0]+wp->font->inc_x-1;
  788.   t[3] = t[7] = t[1]+wp->font->inc_y-1;
  789.   vro_cpyfm(screen_handle, FM_INVERT, t, &wp->wi_mf, &wp->wi_mf);
  790.   w_update(wp, FM_COPY, wp->cur_x, wp->cur_y, wp->font->inc_x, wp->font->inc_y);
  791. }
  792.   
  793. /* w_output prints a string onto the window.  The string may
  794.  * contain control chars and escape sequences.  Its length is given,
  795.  * so you can even output NULs.
  796.  */
  797. void
  798. w_output(wp, ptr, charcount)
  799. struct wi_str *wp;
  800. unsigned char *ptr;
  801. short charcount;
  802. {
  803.   int w_handle;
  804.   unsigned char ch;
  805.   int inc_x, cur_x;
  806.   int state;
  807.   int inc_y, cur_y;
  808.   int t[8];
  809.   int f_x, f_y, f_mod;
  810.   int scrolled;        /* Number of scrolling operations delayed */
  811.   int xsiz, ysiz;/* Size in chars of terminal emulation for this window*/
  812.   register unsigned char *sptr;
  813.   register unsigned long *dptr;
  814.   register unsigned long mask;
  815.   register int shift;
  816.   register unsigned long val;
  817.   int count = 0;
  818.   char * fdata;
  819.   long width;
  820.   char * wimfptr;
  821.   int moffincx;
  822.   unsigned char * savptr;
  823.  
  824.   if (!wp->font) return;
  825.   state = wp->state;
  826.   inc_x = wp->font->inc_x;
  827.   inc_y = wp->font->inc_y;
  828.   xsiz = wp->x_chrs;
  829.   ysiz = wp->y_chrs;
  830.   f_x = cur_x = wp->cur_x;
  831.   f_y = cur_y = wp->cur_y;
  832.  
  833.   /*
  834.    * This sets "hard update" any time the bottom N lines of the buffer are
  835.    * being used -- that is, the overflow below the visible screen. This is
  836.    * seven lines in 8 when you're doing glass-tty scrolling things.  This
  837.    * is wrong & slow.
  838.    */
  839.  
  840.   scrolled = wp->top_y/inc_y;
  841.  
  842.   fdata = wp->font->f_data;
  843.   width = 2 * wp->wi_mf.wwords;
  844.   wimfptr = ((char *) (wp-> wi_mf.ptr)) - 2;
  845.   moffincx = wp->m_off + inc_x - 1;
  846.   f_mod = 0;
  847.   savptr = ptr;
  848.   w_handle = wp->aes_handle;
  849.  
  850.   if (wp->curstate) {
  851.     w_flash(wp, 0);
  852.   }
  853.  
  854.   while (charcount--) {
  855.     ch = *ptr++;
  856.     switch (state) {
  857.     case S_NORMAL:
  858.       if (ch >= ' ') {
  859.     if (wp->insmode) { /* open space for character */
  860.       t[0] = cur_x + wp->m_off;
  861.       t[1] = t[5] = cur_y;
  862.       t[2] = (xsiz - 1) * inc_x + wp->m_off - 1;
  863.       t[3] = t[7] = cur_y + inc_y - 1;
  864.       t[4] = t[0] + inc_x;
  865.       t[6] = t[2] + inc_x;
  866.       vro_cpyfm(screen_handle, FM_COPY, t, &wp->wi_mf, &wp->wi_mf);
  867.     }
  868.  
  869.     /* paint the character (only if it's in range for this font) */
  870.     if (ch < wp->font->nchars) {
  871.         sptr = (unsigned char *)(fdata+ch*16);
  872.         dptr = (unsigned long *)(wimfptr + cur_y*width
  873.                          + (((moffincx + cur_x)>>4)<<1));
  874.         shift = 15 - ((moffincx + cur_x)&15);
  875.  
  876.         /* to get overstrike, set mask to -1 */
  877.         mask = (-1L<<(shift+inc_x)|(1<<shift)-1);
  878.         if (wp->inverse) {
  879.         for (count = inc_y; count; count--) {
  880.             val = ((long)(*sptr++))<<shift ^ ~mask;
  881.             *dptr = (*dptr&mask)|val;
  882.             ((char *)dptr) += width;
  883.         }
  884.         } else {
  885.         for (count = inc_y; count; count--) {
  886.             val = ((long)(*sptr++))<<shift;
  887.             *dptr = (*dptr&mask)|val;
  888.             ((char *)dptr) += width;
  889.         }
  890.         }
  891.     }
  892.     cur_x += inc_x;
  893.     f_mod = 1;
  894.     if (cur_x > inc_x * xsiz) { /* autowrap */
  895.       if (wp->discard) {
  896.         cur_x -= inc_x; /* back to last char position */
  897.       }
  898.       else {
  899.         cur_y += inc_y;
  900.         if (cur_y >= wp->top_y + inc_y * ysiz) {
  901.         wp->top_y += inc_y;
  902.         ++ scrolled;
  903.         }
  904.         if (! scrolled) {
  905.         w_update(wp, FM_COPY, f_x, f_y, cur_x-f_x, inc_y);
  906.         f_mod = 0;
  907.         }
  908.         cur_x = X0;
  909.  
  910.         f_x = cur_x;
  911.         f_y = cur_y;
  912.       }
  913.     }
  914.       } else { /* not printable character */
  915.     /*
  916.      * If you've modified the screen in this incarnation and you aren't
  917.      * "scrolled", update before any non-printing character.  This
  918.      * appears to call w_update for the line you're on, from the X you
  919.      * started from to the X you're at now.  I think this is
  920.      * inefficient, but I'm not sure yet.  If you're in insert mode,
  921.      * update the whole line from the starting X to the end of the
  922.      * line.
  923.      *
  924.      * I changed this to set "scrolled" if you get here and f_mod is
  925.      * TRUE.  That means simple updates on one line (no non-printing
  926.      * chars) don't happen in "scrolled" mode, but anything more
  927.      * complicated does.  This is also conditional on jerky_updates,
  928.      * which is the visual result.
  929.      */
  930.     if (f_mod && !scrolled) {
  931.       if (jerky_updates) scrolled = 1;
  932.       else {
  933.         if (wp->insmode)
  934.           w_update(wp, FM_COPY, f_x, f_y, xsiz * inc_x-f_x, inc_y);
  935.         else
  936.           w_update(wp, FM_COPY, f_x, f_y, cur_x - f_x, inc_y);
  937.         f_mod = 0;
  938.       }
  939.     }
  940.     switch (ch) {
  941.      case '\007':    /* Bell */
  942.       if (audibell)
  943.         (void)Bconout(2, '\007');
  944.       if (visibell) {
  945.         w_redraw(wp, FM_INVERT, wp->x, wp->y, wp->w, wp->h);
  946.         w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h);
  947.         /* Should clear flag to prevent need for next update? */
  948.       }
  949.       break;
  950.  
  951.      case '\r':    /* Carriage Return */
  952.       cur_x = X0;
  953.       break;
  954.  
  955.      case '\b':    /* Backspace */
  956.       if (cur_x>X0) cur_x -= inc_x;
  957.       break;
  958.  
  959.      case '\n':    /* Newline */
  960.       cur_y += inc_y;
  961.       if (cur_y >= inc_y * ysiz + wp->top_y)
  962.       {
  963.         wp->top_y += inc_y;
  964.         ++ scrolled;
  965.       }
  966.       break;
  967.  
  968.      case '\t':    /* Tab */
  969.       cur_x = ((cur_x/inc_x/8+1))*inc_x*8+X0;
  970.       break;
  971.  
  972.      case '\033':    /* ESC */
  973.       state = S_ESC;
  974.       count = 0; /* count is used for insert or delete line */
  975.       break;
  976.     }
  977.     f_x = cur_x;
  978.     f_y = cur_y;
  979.       }
  980.       break;
  981.  
  982.     case S_ESC:
  983.       switch (ch) {
  984.     case 'H':    /* Home */
  985.       cur_x = X0;
  986.       cur_y = wp->top_y;
  987.       state = S_NORMAL;
  988.       break;
  989.  
  990.     case 'A':    /* Cursor Up */
  991.     case 'I':    /* Reverse Index (doesn't reverse scroll yet) */
  992.       if (cur_y!=wp->top_y) {
  993.         cur_y -= inc_y;
  994.       }
  995.       state = S_NORMAL;
  996.       break;
  997.  
  998.     case 'B':    /* Cursor Down */
  999.       if ((cur_y + inc_y) < (wp->top_y + (inc_y * ysiz))) {
  1000.         cur_y += inc_y;
  1001.       }
  1002.       state = S_NORMAL;
  1003.       break;
  1004.  
  1005.     case 'C':    /* Cursor Right */
  1006.       if (cur_x < (xsiz - 1) * inc_x) cur_x += inc_x;
  1007.       state = S_NORMAL;
  1008.       break;
  1009.  
  1010.     case 'D':    /* Cursor Left */
  1011.       if (cur_x > X0) cur_x -= inc_x;
  1012.       state = S_NORMAL;
  1013.       break;
  1014.  
  1015.         case 'b':    /* ST52 color change (foreground) */
  1016.       state = S_FG;
  1017.       break;
  1018.         case 'c':    /* ST52 color change (background) */
  1019.       state = S_BG;
  1020.       break;
  1021.  
  1022.        case 'E':        /* Clear Screen */
  1023.     f_x = cur_x = X0;
  1024.     wp->top_y = f_y = cur_y = Y0;
  1025.     wp->inverse = 0;
  1026.     wp->insmode = 0;
  1027.  
  1028.     lineerase(wp, 0, ysiz - 1 + MAXSCROLLED);
  1029.     ++ scrolled;
  1030.     state = S_NORMAL;
  1031.     break;
  1032.  
  1033.        case 'j':        /* AKP: save cursor location */
  1034.     wp->save_x = cur_x;
  1035.     wp->save_y = cur_y;
  1036.     state = S_NORMAL;
  1037.     break;
  1038.        case 'k':        /* AKP: restore saved location */
  1039.         f_x = cur_x = wp->save_x;
  1040.         f_x = cur_y = wp->save_y;
  1041.         state = S_NORMAL;
  1042.         break;
  1043.  
  1044.        case 'd':        /* Clear from beginning of screen */
  1045.     lineerase(wp, 0,cur_y/inc_y);    /* clear top to this line */
  1046.     ++scrolled;
  1047.     /* fall through */
  1048.        case 'o':        /* Clear from beginning of line */
  1049.     t[0] = t[4] = wp->m_off;        /* init X */
  1050.     t[1] = t[5] = cur_y;            /* init Y */
  1051.     t[2] = t[6] = cur_x + wp->m_off;    /* final X */
  1052.     t[3] = t[7] = cur_y+inc_y-1;
  1053.     vro_cpyfm(screen_handle, FM_CLEAR, t, &wp->wi_mf, &wp->wi_mf);
  1054.     ++scrolled;
  1055.     state = S_NORMAL;
  1056.     break;
  1057.  
  1058.        case 'l':        /* erase entire line, cursor to left */
  1059.         t[0] = t[4] = wp->m_off;
  1060.         t[1] = t[5] = cur_y;
  1061.         t[2] = t[6] = X0-1 + xsiz*inc_x + wp->m_off;
  1062.         t[3] = t[7] = cur_y+inc_y-1;
  1063.         vro_cpyfm(screen_handle, FM_CLEAR, t, &wp->wi_mf, &wp->wi_mf);
  1064.     ++scrolled;
  1065.     cur_x = X0;
  1066.     state = S_NORMAL;
  1067.     break;
  1068.  
  1069.        case 'e':        /* enable cursor */
  1070.         wp->cursor_hidden = 0;
  1071.         state = S_NORMAL;
  1072.         break;
  1073.  
  1074.        case 'f':        /* disable cursor */
  1075.         wp->cursor_hidden = 1;
  1076.         state = S_NORMAL;
  1077.         break;
  1078.  
  1079.        case 'J':        /* Clear to End of Screen */
  1080.     lineerase(wp, cur_y / inc_y + 1, ysiz - 1 + wp->top_y / inc_y);
  1081.     if (! scrolled)
  1082.       w_update(wp, FM_COPY, X0, cur_y + inc_y, xsiz*inc_x, ysiz*inc_y);
  1083.     /* fall through */
  1084.        case 'K':        /* Clear to End of Line */
  1085.     t[0] = t[4] = cur_x + wp->m_off;
  1086.     t[1] = t[5] = cur_y;
  1087.     t[2] = t[6] = X0-1 + xsiz*inc_x +wp->m_off;
  1088.     t[3] = t[7] = cur_y+inc_y-1;
  1089.     vro_cpyfm(screen_handle, FM_CLEAR, t, &wp->wi_mf, &wp->wi_mf);
  1090.     if (! scrolled)
  1091.       w_update(wp, FM_COPY, cur_x, cur_y, xsiz * inc_x - cur_x, inc_y);
  1092.     state = S_NORMAL;
  1093.     break;
  1094.  
  1095.        case 'L':        /* Insert Line */
  1096.        case 'M':        /* Delete Line */
  1097.     if (count == 0) {
  1098.       count = 1;
  1099.       /* Look ahead for contiguous insert/delete line operations */
  1100.       while (*ptr == '\033' && ptr[1] == ch) {
  1101.         ptr +=2;
  1102.         count ++;
  1103.       }
  1104.     }
  1105.     if (ch == 'L')
  1106.       scrolldn(wp, cur_y/inc_y, ysiz-(cur_y-wp->top_y+Y0)/inc_y-count, count);
  1107.     else
  1108.       scrollup(wp, cur_y / inc_y,
  1109.         ysiz - (cur_y - wp->top_y + Y0)/inc_y - count, count);
  1110.     if (! scrolled)
  1111.       w_update(wp, FM_COPY, X0, cur_y, xsiz * inc_x,
  1112.         ysiz * inc_y - cur_y + wp->top_y - Y0);
  1113.     state = S_NORMAL;
  1114.     break;
  1115.  
  1116.       case 'h':        /* Insert Mode */
  1117.     wp->insmode = 1;
  1118.     state = S_NORMAL;
  1119.     break;
  1120.  
  1121.       case 'i':        /* End Insert */
  1122.     wp->insmode = 0;
  1123.     state = S_NORMAL;
  1124.     break;
  1125.  
  1126.       case 'a':        /* Delete Character */
  1127.     t[0] = cur_x + inc_x + wp->m_off;
  1128.     t[1] = t[5] = cur_y;
  1129.     t[2] = X0 - 1 + xsiz * inc_x + wp->m_off;
  1130.     t[3] = t[7] = cur_y+inc_y - 1;
  1131.     t[4] = t[0] - inc_x;
  1132.     t[6] = t[2] - inc_x;
  1133.     vro_cpyfm(screen_handle, FM_COPY, t, &wp->wi_mf, &wp->wi_mf);
  1134.     t[0] = t[4] = X0 + (xsiz - 1) * inc_x + wp->m_off;
  1135.     t[2] = t[6] = t[0] + inc_x - 1;
  1136.     vro_cpyfm(screen_handle, FM_CLEAR, t, &wp->wi_mf, &wp->wi_mf);
  1137.     if (! scrolled)
  1138.       w_update(wp, FM_COPY, cur_x, cur_y, xsiz * inc_x - (cur_x - X0),
  1139.         inc_y);
  1140.     state = S_NORMAL;
  1141.     break;
  1142.  
  1143.       case 'v':        /* clear discard mode */
  1144.         wp->discard = 0;
  1145.         state = S_NORMAL;
  1146.         break;
  1147.  
  1148.       case 'w':        /* set discard mode */
  1149.         wp->discard = 1;
  1150.         state = S_NORMAL;
  1151.         break;
  1152.  
  1153.       case 'Y':        /* Cursor Movement */
  1154.     state = S_ESC1;
  1155.     break;
  1156.  
  1157.       case 'p':        /* Enter Inverse */
  1158.         wp->inverse = 1;
  1159.     state = S_NORMAL;
  1160.     break;
  1161.  
  1162.       case 'q':        /* Exit Inverse */
  1163.     wp->inverse = 0;
  1164.     state = S_NORMAL;
  1165.     break;
  1166.  
  1167.       case 'S':        /* Change Status Line */
  1168.     state = S_STATUS;
  1169.     wp->nuptr = 0;
  1170.     break;
  1171.     
  1172.       default:        /* Unknown escape sequence */
  1173.     state = S_NORMAL;
  1174.     break;
  1175.       }
  1176.       break;
  1177.  
  1178.     case S_FG:
  1179.       wp->fgbg[0] = ch & (ncolors-1);
  1180.       state = S_NORMAL;
  1181.       scrolled = 1;    /* force a hard update */
  1182.       break;
  1183.  
  1184.     case S_BG:
  1185.       wp->fgbg[1] = ch & (ncolors-1);
  1186.       state = S_NORMAL;
  1187.       scrolled = 1;    /* force a hard update */
  1188.       break;
  1189.  
  1190.     case S_ESC1:    /* get line number */
  1191.       if (ch < ' ' || ch >= ' ' + ysiz) ch = ' ';
  1192.       f_y = cur_y = (ch-' ')*inc_y + wp->top_y;
  1193.       state = S_ESC3;
  1194.       break;
  1195.  
  1196.     case S_ESC3:    /* get column number */
  1197.       if (ch < ' ' || ch >= ' ' + xsiz) ch = ' ';
  1198.       f_x = cur_x = (ch-' ')*inc_x +X0;
  1199.       state = S_NORMAL;
  1200.       break;
  1201.  
  1202.     case S_STATUS:
  1203.       if (ch == '\r') {
  1204.     wp->nuname[wp->nuptr] = '\0';
  1205.     w_rename(wp, wp->nuname);
  1206.     state = S_NORMAL;
  1207.       }
  1208.       else if (wp->nuptr < 72) {
  1209.     wp->nuname[wp->nuptr++] = ch;
  1210.       }
  1211.       break;
  1212.     } /* end switch on state */
  1213.  
  1214.     if (scrolled >= MAXSCROLLED) {
  1215.       if (wp->top_y != Y0) {
  1216.     scrollup(wp, 0, ysiz, wp->top_y/inc_y);
  1217.     wp->top_y = Y0;
  1218.     f_y = cur_y = Y0 + (ysiz - 1) * inc_y;
  1219.       }
  1220.       w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h);
  1221.       scrolled = 0;
  1222.     }
  1223.   } /* end while loop for each character */
  1224.  
  1225.   /*
  1226.    * "scrolled" is true if you need to do a hard update, where multiple
  1227.    * lines may have changed.  This used to actually align the virtual
  1228.    * screen with the physical screen only when scrolled >= MAXSCROLLED, but
  1229.    * this meant that seven lines out of eight got hard updates for every
  1230.    * char when typing on a scrolling TTY.  So I align them every time.
  1231.    */
  1232.   if (scrolled) {
  1233.       if (wp->top_y != Y0) {
  1234.     scrollup(wp, 0, ysiz, wp->top_y/inc_y);
  1235.     wp->top_y = Y0;
  1236.     cur_y = Y0 + (ysiz - 1) * inc_y;
  1237.       }
  1238.       w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h);
  1239.   }
  1240.   else {
  1241.     if (f_mod) {
  1242.       if (!wp->insmode)
  1243.     w_update(wp, FM_COPY, f_x, f_y, cur_x - f_x, inc_y);
  1244.       else
  1245.     w_update(wp, FM_COPY, f_x, f_y, xsiz * inc_x-f_x, inc_y);
  1246.     }
  1247.   }
  1248.   wp->cur_x = cur_x;
  1249.   wp->cur_y = cur_y;
  1250.   wp->state = state;
  1251.   w_flash(wp, 1);
  1252. }
  1253.  
  1254. void
  1255. lineerase(wp, first, last)
  1256. register struct wi_str *wp;
  1257. int first, last;
  1258. {
  1259.   register short *p;
  1260.   register long *lp;
  1261.   long count;
  1262.   long linespace = wp->wi_mf.wwords*wp->font->inc_y;
  1263.  
  1264.   p = wp->wi_mf.ptr + first*linespace + Y0*wp->wi_mf.wwords - 1;
  1265.   count = (last-first+1)*linespace;
  1266.   lp = (long *)p;
  1267.   while (count > 7)
  1268.   {
  1269.     *lp++ = 0;
  1270.     *lp++ = 0;
  1271.     *lp++ = 0;
  1272.     *lp++ = 0;
  1273.     count -= 8;
  1274.   }
  1275.   p = (short *)lp;
  1276.   while (--count >= 0)
  1277.     *++p = 0;
  1278. }
  1279.  
  1280. void
  1281. scrollup(wp, first, nlines, amount)
  1282. register struct wi_str *wp;
  1283. int first, nlines, amount;
  1284. {
  1285.   register short *p1, *p2;
  1286.   register long *lp1, *lp2;
  1287.   register long count;
  1288.   int linespace = wp->wi_mf.wwords*wp->font->inc_y;
  1289.  
  1290.   p1 = wp->wi_mf.ptr + first*linespace + Y0*wp->wi_mf.wwords;
  1291.   p2 = p1 + linespace * amount;
  1292.   count = (long)(nlines)*linespace;
  1293.   lp1 = (long *)p1;
  1294.   lp2 = (long *)p2;
  1295.   while (count > 15)
  1296.   {
  1297.     *lp1++ = *lp2++;
  1298.     *lp1++ = *lp2++;
  1299.     *lp1++ = *lp2++;
  1300.     *lp1++ = *lp2++;
  1301.     *lp1++ = *lp2++;
  1302.     *lp1++ = *lp2++;
  1303.     *lp1++ = *lp2++;
  1304.     *lp1++ = *lp2++;
  1305.     count -= 16;
  1306.   }
  1307.   p1 = (short *)lp1;
  1308.   p2 = (short *)lp2;
  1309.   while (--count >= 0)
  1310.     *(p1++) = *(p2++);
  1311.   count = linespace * amount;
  1312.   lp1 = (long *)p1;
  1313.   while (count > 7)
  1314.   {
  1315.     *lp1++ = 0;
  1316.     *lp1++ = 0;
  1317.     *lp1++ = 0;
  1318.     *lp1++ = 0;
  1319.     count -= 8;
  1320.   }
  1321.   p1 = (short *)lp1;
  1322.   while (--count >= 0)
  1323.     *(p1++) = 0;
  1324. }
  1325.  
  1326. void
  1327. scrolldn(wp, first, nlines, amount)
  1328. register struct wi_str *wp;
  1329. int first, nlines, amount;
  1330. {
  1331.   register short *p1, *p2;
  1332.   register long *lp1, *lp2;
  1333.   register long count;
  1334.   long linespace = wp->wi_mf.wwords*wp->font->inc_y;
  1335.  
  1336.   p1 = wp->wi_mf.ptr + (nlines+first+amount)*linespace + Y0*wp->wi_mf.wwords;
  1337.  
  1338.   p2 = p1 - linespace * amount;
  1339.   count = (long)(nlines)*linespace;
  1340.   lp2 = (long *)p2;
  1341.   lp1 = (long *)p1;
  1342.   while (count > 15)
  1343.   {
  1344.     *--lp1 = *--lp2;
  1345.     *--lp1 = *--lp2;
  1346.     *--lp1 = *--lp2;
  1347.     *--lp1 = *--lp2;
  1348.     *--lp1 = *--lp2;
  1349.     *--lp1 = *--lp2;
  1350.     *--lp1 = *--lp2;
  1351.     *--lp1 = *--lp2;
  1352.     count -= 16;
  1353.   }
  1354.   p1 = (short *)lp1;
  1355.   p2 = (short *)lp2;
  1356.   while (--count >= 0)
  1357.     *--p1 = *--p2;
  1358.   count = linespace * amount;
  1359.   lp1 = (long *)p1;
  1360.   while (count > 7)
  1361.   {
  1362.     *--lp1 = 0L;
  1363.     *--lp1 = 0L;
  1364.     *--lp1 = 0L;
  1365.     *--lp1 = 0L;
  1366.     count -= 8;
  1367.   }
  1368.   p1 = (short *)lp1;
  1369.   while (--count >= 0)
  1370.     *--p1 = 0;
  1371. }
  1372.