home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / toswinsc.zoo / textwin.c < prev    next >
C/C++ Source or Header  |  1992-10-27  |  30KB  |  1,257 lines

  1. /*
  2.  * Copyright 1992 Eric R. Smith. All rights reserved.
  3.  * Redistribution is permitted only if the distribution
  4.  * is not for profit, and only if all documentation
  5.  * (including, in particular, the file "copying")
  6.  * is included in the distribution in unmodified form.
  7.  * THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
  8.  * EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
  9.  * FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
  10.  * RISK.
  11.  */
  12. #include "xgem.h"
  13. #include <stdlib.h>
  14.  
  15. #define CLEARED 2        /* redrawing a cleared area */
  16.  
  17. int default_height = 10;    /* default font height (points) */
  18. int default_font = 1;        /* default font (pixels) */
  19. int align_windows = 0;        /* align windows on byte boundaries */
  20.  
  21. /* if a font doesn't define a character, use this one instead */
  22. #define DEFAULT_CHAR '?'
  23.  
  24. static void set_cwidths __PROTO((TEXTWIN *));
  25.  
  26. /* functions for converting x, y pixels to/from character coordinates */
  27. /* NOTES: these functions give the upper left corner; to actually draw
  28.  * a character, they must be adjusted down by t->cbase
  29.  * Also: char2pixel accepts out of range character/column combinations,
  30.  * but pixel2char never will generate such combinations.
  31.  */
  32. void
  33. char2pixel(t, col, row, xp, yp)
  34.     TEXTWIN *t;
  35.     int col, row;
  36.     int *xp, *yp;
  37. {
  38.     short *WIDE = t->cwidths;
  39.     int x;
  40.  
  41.     *yp = t->win->wi_y - t->offy + row * t->cheight;
  42.     if (!WIDE) {
  43.         *xp = t->win->wi_x - t->offx + col * t->cmaxwidth;
  44.     } else if (col >= t->maxx) {
  45.         *xp = t->win->wi_x + t->win->wi_w;
  46.     } else {
  47.         x = t->win->wi_x - t->offx;
  48.         while(--col >= 0) {
  49.             x += WIDE[t->data[row][col]];
  50.         }
  51.         *xp = x;
  52.     }
  53. }
  54.  
  55. void
  56. pixel2char(t, x, y, colp, rowp)
  57.     TEXTWIN *t;
  58.     int x, y, *colp, *rowp;
  59. {
  60.     int col, row, count, nextcount;
  61.     short *WIDE = t->cwidths;
  62.  
  63.     row = (y - t->win->wi_y + t->offy) / t->cheight;
  64.     x = x - t->win->wi_x + t->offx;
  65.  
  66.     if (WIDE == 0) {
  67.         col = x / t->cmaxwidth;
  68.     } else {
  69.         count = 0;
  70.         for (col = 0; col < t->maxx - 1; col++) {
  71.             nextcount = count + WIDE[t->data[row][col]];
  72.             if (count <= x && x < nextcount) break;
  73.             count = nextcount;
  74.         }
  75.     }
  76.     *rowp = row;
  77.     *colp = col;
  78. }
  79.  
  80. static void set_scroll_bars __PROTO((TEXTWIN *));
  81.  
  82. /*
  83.  * draw a (part of a) line on screen, with certain attributes (e.g.
  84.  * inverse video) indicated by "flag". (x, y) is the upper left corner
  85.  * of the box which will contain the line.
  86.  * If "force" is 1, we may assume that the screen is already cleared
  87.  * (this is done in update_screen() for us).
  88.  * SPECIAL CASE: if buf is an empty string, we clear from "x" to
  89.  * the end of the window.
  90.  */
  91. static void
  92. draw_buf(t, buf, x, y, flag, force)
  93.     TEXTWIN *t;
  94.     char *buf;
  95.     int x, y, flag, force;
  96. {
  97.     char *s, *lastnonblank;
  98.     int x2, fillcolor, textcolor;
  99.     int texteffects;
  100.     short *WIDE = t->cwidths;
  101.     int temp[4];
  102.  
  103.     fillcolor = flag & CBGCOL;
  104.     textcolor = (flag & CFGCOL) >> 4;
  105.     texteffects = (flag & CEFFECTS) >> 8;
  106.  
  107. #ifdef STIPPLE_SELECT
  108.     if (flag & CINVERSE) {    /* swap foreground and background */
  109.         x2 = fillcolor; fillcolor = textcolor; textcolor = x2;
  110.     }
  111. #else
  112.     if (flag & (CINVERSE|CSELECTED)) {    /* swap foreground and background */
  113.         x2 = fillcolor; fillcolor = textcolor; textcolor = x2;
  114.     }
  115. #endif
  116.     x2 = x;
  117.     s = buf;
  118.     if (*s) {
  119.         lastnonblank = s-1;
  120.         while (*s) {
  121.             if (*s != ' ') lastnonblank = s;
  122.             if (WIDE)
  123.                 x2 += WIDE[*s];
  124.             else
  125.                 x2 += t->cmaxwidth;
  126.             s++;
  127.         }
  128.         lastnonblank++;
  129.         if (!(flag & CE_UNDERLINE))
  130.             *lastnonblank = 0;
  131.     } else {
  132.         x2 = t->win->wi_x + t->win->wi_w;
  133.     }
  134.  
  135.     set_wrmode(2);        /* transparent text */
  136.     if (fillcolor != 0 || (force != CLEARED)) {
  137.     /* the background may not be set correctly, so we do it here */
  138.         temp[0] = x;
  139.         temp[1] = y;
  140.         temp[2] = x2 - 1;
  141.         temp[3] = y + t->cheight - 1;
  142.         set_fillcolor(fillcolor);
  143.         set_fillstyle(1, 1);        /* fill the area completely */
  144.         v_bar(vdi_handle, temp);
  145.     }
  146.  
  147. /* skip leading blanks -- we don't need to draw them again! */
  148.     if (!(flag & CE_UNDERLINE)) {
  149.         while (*buf == ' ') {
  150.             buf++;
  151.             x += WIDE ? WIDE[' '] : t->cmaxwidth;
  152.         }
  153.     }
  154.  
  155.     if (*buf) {
  156.         set_textcolor(textcolor);
  157.         set_texteffects(texteffects);
  158.         v_gtext(vdi_handle, x, y + t->cbase, buf);
  159.     }
  160.  
  161. #ifdef STIPPLE_SELECT
  162.     if (flag & CSELECTED) {        /* put in the pattern */
  163.         set_wrmode(2);        /* 'OR' the pattern */
  164.         set_fillstyle(2, 2);
  165.         set_fillcolor(textcolor);
  166.         v_bar(vdi_handle, temp);
  167.     }
  168. #endif
  169. }
  170.  
  171. /*
  172.  * update the characters on screen between "firstline,firstcol" and 
  173.  * "lastline-1,lastcol-1" (inclusive)
  174.  * if force == 1, the redraw must occur, otherwise it occurs only for
  175.  * "dirty" characters. Note that we assume here that clipping
  176.  * rectanges and wind_update() have already been set for us.
  177.  */
  178.  
  179. static void
  180. update_chars(t, firstcol, lastcol, firstline, lastline, force)
  181.     TEXTWIN *t;
  182.     int firstcol, lastcol, firstline, lastline, force;
  183. {
  184. #define CBUFSIZ 127
  185.     UCHAR buf[CBUFSIZ+1], c;
  186.     int px, py, ax, i, cnt, flag, bufwidth;
  187.     short *WIDE = t->cwidths;
  188.     int lineforce = 0;
  189.     int curflag;
  190.  
  191. #define flushbuf()    \
  192.     {    buf[i] = 0;    \
  193.          draw_buf(t, buf, px, py, flag, lineforce); \
  194.          px += bufwidth; \
  195.          i = bufwidth = 0; \
  196.     }
  197.  
  198. /* make sure the font is set correctly */
  199.     set_font(t->cfont, t->cpoints);
  200.  
  201. /* find the place to start writing */
  202.     char2pixel(t, firstcol, firstline, &ax, &py);
  203.  
  204. /* now write the characters we need to */
  205.     while (firstline < lastline) {
  206. /* if no characters on the line need re-writing, skip the loop */
  207.         if (!force && t->dirty[firstline] == 0) {
  208.             py += t->cheight;
  209.             firstline++;
  210.             continue;
  211.         }
  212.         px = ax;
  213. /*
  214.  * now, go along collecting characters to write into the buffer
  215.  * we add a character to the buffer if and only if (1) the
  216.  * character's attributes (inverse video, etc.) match the
  217.  * attributes of the character already in the buffer, and
  218.  * (2) the character needs redrawing. Otherwise, if there are
  219.  * characters in the buffer, we flush the buffer.
  220.  */
  221.         i = bufwidth = 0;
  222.         cnt = firstcol;
  223.         flag = 0;
  224.         lineforce = force;
  225.         if (!lineforce && (t->dirty[firstline] & ALLDIRTY))
  226.             lineforce = 1;
  227.         while (cnt < lastcol) {
  228.             c = t->data[firstline][cnt];
  229.             if (lineforce ||
  230.                (t->cflag[firstline][cnt] & (CDIRTY|CTOUCHED))) {
  231. /* yes, this character needs drawing */
  232. /* if the font is proportional and the character has really changed,
  233.  * then all remaining characters will have to be redrawn, too
  234.  */
  235.             if (WIDE && (lineforce == 0) &&
  236.                 (t->cflag[firstline][cnt] & CDIRTY))
  237.                 lineforce = 1;
  238. /* watch out for characters that can't be drawn in this font */
  239.             if (c < t->minADE || c > t->maxADE)
  240.                 c = DEFAULT_CHAR;
  241.             curflag = t->cflag[firstline][cnt] & ~(CDIRTY|CTOUCHED);
  242.             if (flag == curflag) {
  243.                 buf[i++] = c;
  244.                 bufwidth += (WIDE ? WIDE[c] : t->cmaxwidth);
  245.                 if (i == CBUFSIZ) {
  246.                 flushbuf();
  247.                 }
  248.             } else {
  249.                 if (i) {
  250.                 flushbuf();
  251.                 }
  252.                 flag = curflag;
  253.                 buf[i++] = c;
  254.                 bufwidth += (WIDE ? WIDE[c] : t->cmaxwidth);
  255.             }
  256.             } else {
  257.             if (i) {
  258.                 flushbuf();
  259.             }
  260.             px += (WIDE ? WIDE[c] : t->cmaxwidth);
  261.             }
  262.             cnt++;
  263.         }
  264.         if (i) {
  265.             flushbuf();
  266.         }
  267.         if (WIDE) {        /* the line's 'tail' */
  268.             draw_buf(t, "", px, py, t->cflag[firstline][t->maxx-1],
  269.                 lineforce);
  270.         }
  271.         py += t->cheight;
  272.         firstline++;
  273.     }
  274. }
  275.  
  276. /*
  277.  * mark_clean: mark a window as having been completely updated
  278.  */
  279.  
  280. void
  281. mark_clean(t)
  282.     TEXTWIN *t;
  283. {
  284.     int line, col;
  285.  
  286.     for (line = 0; line < t->maxy; line++) {
  287.         if (t->dirty[line] == 0)
  288.             continue;
  289.         for (col = 0; col < t->maxx; col++) {
  290.             t->cflag[line][col] &= ~(CDIRTY|CTOUCHED);
  291.         }
  292.         t->dirty[line] = 0;
  293.     }
  294. }
  295.  
  296. /*
  297.  * redraw all parts of window v which are contained within the
  298.  * given rectangle. Assumes that the clipping rectange has already
  299.  * been set correctly.
  300.  * NOTE: more than one rectangle may cover the same area, so we
  301.  * can't mark the window clean during the update; we have to do
  302.  * it in a separate routine (mark_clean)
  303.  */
  304.  
  305. static MFDB scr_mfdb;    /* left NULL so it refers to the screen by default */
  306.  
  307. static void
  308. update_screen(t, xc, yc, wc, hc, force)
  309.     TEXTWIN *t;
  310.     int xc, yc, wc, hc;
  311.     int force;
  312. {
  313.     int firstline, lastline, firstscroll;
  314.     int firstcol, lastcol;
  315.     int pxy[8];
  316.     int scrollht = 0;
  317.  
  318. /* if t->scrolled is set, then the output routines faked the "dirty"
  319.  * flags on the scrolled lines under the assumption that we would
  320.  * do a blit scroll; so we do it here.
  321.  */
  322.     if ((force == 0) && t->scrolled &&
  323.         (scrollht = t->scrolled * t->cheight) < hc) {
  324.         pxy[0] = xc;
  325.         pxy[1] = yc + scrollht;
  326.         pxy[2] = xc + wc - 1;
  327.         pxy[3] = yc + hc - 1;
  328.         pxy[4] = xc;
  329.         pxy[5] = yc;
  330.         pxy[6] = pxy[2];
  331. #if 0
  332.         pxy[7] = pxy[1]-1;
  333. #else
  334.         pxy[7] = pxy[3] - scrollht;
  335. #endif
  336. #define FM_COPY 3
  337. #define FM_CLEAR 0
  338.         vro_cpyfm(vdi_handle, FM_COPY, pxy, &scr_mfdb, &scr_mfdb);
  339.     }
  340.  
  341. /* if `force' is set, clear the area to be redrawn -- it looks better */
  342.     if (force == CLEARED) {
  343.         pxy[4] = pxy[0] = xc;
  344.         pxy[5] = pxy[1] = yc;
  345.         pxy[6] = pxy[2] = xc + wc - 1;
  346.         pxy[7] = pxy[3] = yc + hc - 1;
  347.         vro_cpyfm(vdi_handle, FM_CLEAR, pxy, &scr_mfdb, &scr_mfdb);
  348.     }
  349.  
  350. /* convert from on-screen coordinates to window rows & columns */
  351.     pixel2char(t, xc, yc, &firstcol, &firstline);
  352.  
  353.     if (firstline < 0) firstline = 0;
  354.     else if (firstline >= t->maxy) firstline = t->maxy - 1;
  355.  
  356.     lastline = 1 + firstline + (hc + t->cheight - 1) / t->cheight;
  357.     if (lastline > t->maxy) lastline = t->maxy;
  358.  
  359. /* kludge for proportional fonts */
  360.     if (t->cwidths) {
  361.         firstcol = 0;
  362.         lastcol = t->maxx;
  363.     } else {
  364.         pixel2char(t, xc+wc+t->cmaxwidth-1, yc, &lastcol, &firstline);
  365.     }
  366.  
  367. /* if t->scrolled is set, the last few lines *must* be updated */
  368.     if (t->scrolled && force == 0) {
  369.         firstscroll = firstline + (hc - scrollht)/t->cheight;
  370.         if (firstscroll <= firstline) {
  371.             force = TRUE;
  372.         } else {
  373.             update_chars(t, firstcol, lastcol, firstscroll, lastline, TRUE);
  374.             lastline = firstscroll;
  375.         }
  376.     }
  377.     update_chars(t, firstcol, lastcol, firstline, lastline, force);
  378. }
  379.  
  380. /*
  381.  * redraw all parts of a window that need redrawing; this is called
  382.  * after, for example, writing some text into the window
  383.  */
  384.  
  385. void
  386. refresh_textwin(t)
  387.     TEXTWIN *t;
  388. {
  389.     WINDOW *v = t->win;
  390.     GRECT    t1, t2;
  391.  
  392.     if (v->wi_handle < 0) return;    /* window not visible */
  393.     wind_update(TRUE);
  394.     hide_mouse();
  395.     t2.g_x = t->win->wi_x;
  396.     t2.g_y = t->win->wi_y;
  397.     t2.g_w = t->win->wi_w;
  398.     t2.g_h = t->win->wi_h;
  399.     wind_get(v->wi_handle, WF_FIRSTXYWH,
  400.          &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h);
  401.  
  402.     while (t1.g_w && t1.g_h) {
  403.         if (rc_intersect(&t2, &t1)) {
  404.             set_clip(t1.g_x, t1.g_y, t1.g_w, t1.g_h);
  405.             update_screen(t, t1.g_x, t1.g_y, t1.g_w, t1.g_h, FALSE);
  406.           }
  407.         wind_get(v->wi_handle, WF_NEXTXYWH, &t1.g_x, &t1.g_y,
  408.              &t1.g_w, &t1.g_h);
  409.     }
  410.     t->scrolled = t->nbytes = t->draw_time = 0;
  411.     show_mouse();
  412.     mark_clean(t);
  413.     wind_update(FALSE);
  414. }
  415.  
  416. /*
  417.  * Methods for reacting to user events
  418.  */
  419.  
  420.  
  421. /* draw part of a window */
  422.  
  423. static void
  424. draw_textwin(v, x, y, w, h)
  425.     WINDOW *v;
  426.     int x, y, w, h;
  427. {
  428.     TEXTWIN *t = v->extra;
  429.  
  430.     t->scrolled = 0;
  431.     update_screen(v->extra, x, y, w, h, CLEARED);
  432.     t->nbytes = t->draw_time = 0;
  433. }
  434.  
  435. /* close a window (called when the closed box is clicked on) */
  436.  
  437. static void
  438. close_textwin(v)
  439.     WINDOW *v;
  440. {
  441.     void destroy_textwin();
  442.  
  443.     destroy_textwin(v->extra);
  444. }
  445.  
  446. /* resize a window to its "full" size */
  447.  
  448. static void
  449. full_textwin(v)
  450.     WINDOW *v;
  451. {
  452.     int newx, newy, neww, newh;
  453.  
  454.     if (v->flags & WFULLED) {
  455.         wind_get(v->wi_handle, WF_PREVXYWH, &newx, &newy, &neww,
  456.              &newh);
  457.     } else {
  458.         wind_get(v->wi_handle, WF_FULLXYWH, &newx, &newy, &neww,
  459.             &newh);
  460.     }
  461.  
  462.     wind_calc(WC_WORK, v->wi_kind, newx, newy, neww, newh,
  463.           &v->wi_x, &v->wi_y, &v->wi_w, &v->wi_h);
  464.     if (align_windows && (v->wi_x & 7)) {
  465.         v->wi_x &= ~7;
  466.         wind_calc(WC_BORDER, v->wi_kind, v->wi_x, v->wi_y, v->wi_w,
  467.             v->wi_h, &newx, &newy, &neww, &newh);
  468.     }
  469.     wind_set(v->wi_handle, WF_CURRXYWH, newx, newy, neww, newh);
  470.     v->flags ^= WFULLED;
  471.     set_scroll_bars(v->extra);
  472. }
  473.  
  474. /* resize a window */
  475.  
  476. static void redo __PROTO(( TEXTWIN * ));
  477.  
  478. static void
  479. move_textwin(v, x, y, w, h)
  480.     WINDOW *v;
  481.     int x, y, w, h;
  482. {
  483.     int fullx, fully, fullw, fullh;
  484.  
  485.     wind_get(v->wi_handle, WF_FULLXYWH, &fullx, &fully, &fullw, &fullh);
  486.  
  487.     if (w > fullw) w = fullw;
  488.     if (h > fullh) h = fullh;
  489.     wind_calc(WC_WORK, v->wi_kind, x, y, w, h, &v->wi_x,
  490.         &v->wi_y, &v->wi_w, &v->wi_h);
  491.     if (align_windows) {
  492.         v->wi_x &= ~7;
  493.         wind_calc(WC_BORDER, v->wi_kind, v->wi_x, v->wi_y, v->wi_w, v->wi_h,
  494.             &x, &y, &w, &h);
  495.     }
  496.     wind_set(v->wi_handle, WF_CURRXYWH, x, y, w, h);
  497.     if (w != fullw || h != fullh)
  498.         v->flags &= ~WFULLED;
  499. }
  500.  
  501. static void
  502. size_textwin(v, x, y, w, h)
  503.     WINDOW *v;
  504.     int x, y, w, h;
  505. {
  506.     TEXTWIN *t = v->extra;
  507.  
  508.     (*v->moved)(v, x, y, w, h);
  509.     set_scroll_bars(t);
  510. }
  511.  
  512. /*
  513.  * handle an arrow event to a window
  514.  */
  515.  
  516. static void
  517. newxoff(t, x)
  518.     TEXTWIN *t;
  519.     int x;
  520. {
  521.     t->offx = x;
  522.     set_scroll_bars(t);
  523. }
  524.  
  525. static void
  526. newyoff(t, y)
  527.     TEXTWIN *t;
  528.     int y;
  529. {
  530.     t->offy = y;
  531.     set_scroll_bars(t);
  532. }
  533.  
  534. /*
  535.  * redisplay a text window in its entirety, but without pre-clearing
  536.  * areas: this looks better when arrowing and paging
  537.  */
  538.  
  539. static void
  540. redo(t)
  541.     TEXTWIN *t;
  542. {
  543.     WINDOW *v;
  544.     int xc, yc, wc, hc;
  545.     GRECT    t1, t2;
  546.  
  547.     v = t->win;
  548.     xc = v->wi_x; yc = v->wi_y; wc = v->wi_w; hc = v->wi_h;
  549.  
  550.     wind_update(TRUE);
  551.     hide_mouse();
  552.     t2.g_x = xc;
  553.     t2.g_y = yc;
  554.     t2.g_w = wc;
  555.     t2.g_h = hc;
  556.     wind_get(v->wi_handle, WF_FIRSTXYWH,
  557.          &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h);
  558.  
  559.     while (t1.g_w && t1.g_h) {
  560.         if (rc_intersect(&t2, &t1)) {
  561.             set_clip(t1.g_x, t1.g_y, t1.g_w, t1.g_h);
  562.             update_screen(t, t1.g_x, t1.g_y, t1.g_w, t1.g_h, TRUE);
  563.           }
  564.         wind_get(v->wi_handle, WF_NEXTXYWH, &t1.g_x, &t1.g_y,
  565.              &t1.g_w, &t1.g_h);
  566.     }
  567.     t->scrolled = t->nbytes = t->draw_time = 0;
  568.     show_mouse();
  569.     mark_clean(t);
  570.     wind_update(FALSE);
  571. }
  572.  
  573. #define UP 0
  574. #define DOWN 1
  575.  
  576. #define scrollup(t, off) scrollupdn(t, off, UP)
  577. #define scrolldn(t, off) scrollupdn(t, off, DOWN)
  578.  
  579. static void
  580. scrollupdn(t, off, direction)
  581.     TEXTWIN *t;
  582.     int off;
  583.     int direction;
  584. {
  585.     WINDOW *v;
  586.     int xc, yc, wc, hc;
  587.     GRECT    t1, t2;
  588.     int pxy[8];
  589.  
  590.     v = t->win;
  591.     xc = v->wi_x; yc = v->wi_y; wc = v->wi_w; hc = v->wi_h;
  592.  
  593.     if (off <= 0) {
  594.         return;
  595.     }
  596.  
  597.     wind_update(TRUE);
  598.     hide_mouse();
  599.     t2.g_x = xc;
  600.     t2.g_y = yc;
  601.     t2.g_w = wc;
  602.     t2.g_h = hc;
  603.     wind_get(v->wi_handle, WF_FIRSTXYWH,
  604.          &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h);
  605.  
  606.     while (t1.g_w && t1.g_h) {
  607.         if (rc_intersect(&t2, &t1)) {
  608.             set_clip(t1.g_x, t1.g_y, t1.g_w, t1.g_h);
  609.             if (off >= t1.g_h) {
  610.                 update_screen(t, t1.g_x, t1.g_y, t1.g_w, t1.g_h, TRUE);
  611.             } else {
  612.                 if (direction  == UP) {
  613.                     pxy[0] = t1.g_x;    /* "from" address */
  614.                     pxy[1] = t1.g_y + off;
  615.                     pxy[2] = t1.g_x + t1.g_w - 1;
  616.                     pxy[3] = t1.g_y + t1.g_h - 1;
  617.                     pxy[4] = t1.g_x;    /* "to" address */
  618.                     pxy[5] = t1.g_y;
  619.                     pxy[6] = t1.g_x + t1.g_w - 1;
  620.                     pxy[7] = t1.g_y + t1.g_h - off - 1;
  621.                 } else {
  622.                     pxy[0] = t1.g_x;
  623.                     pxy[1] = t1.g_y;
  624.                     pxy[2] = t1.g_x + t1.g_w - 1;
  625.                     pxy[3] = t1.g_y + t1.g_h - off - 1;
  626.                     pxy[4] = t1.g_x;
  627.                     pxy[5] = t1.g_y + off;
  628.                     pxy[6] = t1.g_x + t1.g_w - 1;
  629.                     pxy[7] = t1.g_y + t1.g_h - 1;
  630.                 }
  631.                 vro_cpyfm(vdi_handle, FM_COPY, pxy, &scr_mfdb, &scr_mfdb);
  632.                 if (direction == UP)
  633.                     update_screen(t, t1.g_x, pxy[7], t1.g_w, off, TRUE);
  634.                 else
  635.                     update_screen(t, t1.g_x, t1.g_y, t1.g_w, off, TRUE);
  636.             }
  637.           }
  638.         wind_get(v->wi_handle, WF_NEXTXYWH, &t1.g_x, &t1.g_y,
  639.              &t1.g_w, &t1.g_h);
  640.     }
  641.     show_mouse();
  642.     wind_update(FALSE);
  643. }
  644.  
  645. #define LEFT 0
  646. #define RIGHT 1
  647.  
  648. #define scrolllf(t, off) scrollleftright(t, off, LEFT)
  649. #define scrollrt(t, off) scrollleftright(t, off, RIGHT)
  650.  
  651. static void
  652. scrollleftright(t, off, direction)
  653.     TEXTWIN *t;
  654.     int off;
  655.     int direction;
  656. {
  657.     WINDOW *v;
  658.     int xc, yc, wc, hc;
  659.     GRECT    t1, t2;
  660.     int pxy[8];
  661.  
  662.     v = t->win;
  663.     xc = v->wi_x; yc = v->wi_y; wc = v->wi_w; hc = v->wi_h;
  664.  
  665.     if (off <= 0) {
  666.         return;
  667.     }
  668.  
  669.     wind_update(TRUE);
  670.     hide_mouse();
  671.     t2.g_x = xc;
  672.     t2.g_y = yc;
  673.     t2.g_w = wc;
  674.     t2.g_h = hc;
  675.     wind_get(v->wi_handle, WF_FIRSTXYWH,
  676.          &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h);
  677.  
  678.     while (t1.g_w && t1.g_h) {
  679.         if (rc_intersect(&t2, &t1)) {
  680.             set_clip(t1.g_x, t1.g_y, t1.g_w, t1.g_h);
  681.             if (off >= t1.g_w) {
  682.                 update_screen(t, t1.g_x, t1.g_y, t1.g_w, t1.g_h, TRUE);
  683.             } else {
  684.                 if (direction == LEFT) {
  685.                     pxy[0] = t1.g_x + off;    /* "from" address */
  686.                     pxy[1] = t1.g_y;
  687.                     pxy[2] = t1.g_x + t1.g_w - 1;
  688.                     pxy[3] = t1.g_y + t1.g_h - 1;
  689.                     pxy[4] = t1.g_x;    /* "to" address */
  690.                     pxy[5] = t1.g_y;
  691.                     pxy[6] = t1.g_x + t1.g_w - off - 1;
  692.                     pxy[7] = t1.g_y + t1.g_h - 1;
  693.                 } else {
  694.                     pxy[0] = t1.g_x;
  695.                     pxy[1] = t1.g_y;
  696.                     pxy[2] = t1.g_x + t1.g_w - off - 1;
  697.                     pxy[3] = t1.g_y + t1.g_h;
  698.                     pxy[4] = t1.g_x + off;
  699.                     pxy[5] = t1.g_y;
  700.                     pxy[6] = t1.g_x + t1.g_w - 1;
  701.                     pxy[7] = t1.g_y + t1.g_h - 1;
  702.                 }
  703.                 vro_cpyfm(vdi_handle, FM_COPY, pxy, &scr_mfdb, &scr_mfdb);
  704.                 if (direction == LEFT)
  705.                     update_screen(t, pxy[6], t1.g_y, off, t1.g_h, TRUE);
  706.                 else
  707.                     update_screen(t, t1.g_x, t1.g_y, off, t1.g_h, TRUE);
  708.             }
  709.           }
  710.         wind_get(v->wi_handle, WF_NEXTXYWH, &t1.g_x, &t1.g_y,
  711.              &t1.g_w, &t1.g_h);
  712.     }
  713.     show_mouse();
  714.     wind_update(FALSE);
  715. }
  716.  
  717. static void
  718. arrow_textwin(v, msg)
  719.     WINDOW *v;
  720.     int msg;
  721. {
  722.     TEXTWIN *t = (TEXTWIN *)v->extra;
  723.     int oldoff;
  724.  
  725.     refresh_textwin(t);
  726.  
  727.     switch(msg) {
  728.     case WA_UPPAGE:
  729.         newyoff(t, t->offy - v->wi_h);
  730.         break;
  731.     case WA_DNPAGE:
  732.         newyoff(t, t->offy + v->wi_h);
  733.         break;
  734.     case WA_UPLINE:
  735.         oldoff = t->offy;
  736.         newyoff(t, t->offy - t->cheight);
  737.         scrolldn(t, oldoff - t->offy);
  738.         return;
  739.     case WA_DNLINE:
  740.         oldoff = t->offy;
  741.         newyoff(t, t->offy + t->cheight);
  742.         scrollup(t, t->offy - oldoff);
  743.         return;
  744.     case WA_LFPAGE:
  745.         newxoff(t, t->offx - v->wi_w);
  746.         break;
  747.     case WA_RTPAGE:
  748.         newxoff(t, t->offx + v->wi_w);
  749.         break;
  750.     case WA_LFLINE:
  751.         oldoff = t->offx;
  752.         newxoff(t, t->offx - t->cmaxwidth);
  753.         scrollrt(t, oldoff - t->offx);
  754.         return;
  755.     case WA_RTLINE:
  756.         oldoff = t->offx;
  757.         newxoff(t, t->offx + t->cmaxwidth);
  758.         scrolllf(t, t->offx - oldoff);
  759.         return;
  760.     }
  761.     redo(t);
  762. }
  763.  
  764. /*
  765.  * handle horizontal and vertical slider events for a window
  766.  */
  767.  
  768. static void
  769. hslid_textwin(v, hpos)
  770.     WINDOW *v;
  771.     int hpos;
  772. {
  773.     TEXTWIN *t = (TEXTWIN *)v->extra;
  774.     long width;
  775.     int oldoff;
  776.  
  777.     width = t->cmaxwidth * t->maxx - v->wi_w;
  778.     oldoff = t->offx;
  779.     newxoff(t, (int)( (hpos * width) / 1000 ));
  780.     oldoff -= t->offx;
  781.     if (oldoff < 0)
  782.         scrolllf(t, -oldoff);
  783.     else
  784.         scrollrt(t, oldoff);
  785. }
  786.  
  787. static void
  788. vslid_textwin(v, vpos)
  789.     WINDOW *v;
  790.     int vpos;
  791. {
  792.     TEXTWIN *t = (TEXTWIN *)v->extra;
  793.     long height;
  794.     int oldoff;
  795.  
  796.     height = t->cheight * t->maxy - v->wi_h;
  797.     oldoff = t->offy;
  798.     newyoff(t, (int)( (vpos * height) / 1000));
  799.     oldoff -= t->offy;
  800.     if (oldoff < 0)
  801.         scrollup(t, -oldoff);
  802.     else
  803.         scrolldn(t, oldoff);
  804. }
  805.  
  806. /*
  807.  * correctly set up the horizontal and vertical scroll bars for TEXTWIN
  808.  * t
  809.  */
  810.  
  811. static void
  812. set_scroll_bars(t)
  813.     TEXTWIN *t;
  814. {
  815.     WINDOW *v = t->win;
  816.     int hsize, vsize;
  817.     int hpos, vpos;
  818.     long width, height;
  819.  
  820.     width = t->cmaxwidth * t->maxx;
  821.     height = t->cheight * t->maxy;
  822.  
  823. /* see if the new offset is too big for the window */
  824.     if (t->offx + v->wi_w > width) {
  825.         t->offx  = width - v->wi_w;
  826.     }
  827.     if (t->offx < 0) t->offx = 0;
  828.  
  829.     if (t->offy + v->wi_h > height) {
  830.         t->offy = height - v->wi_h;
  831.     }
  832.     if (t->offy < 0) t->offy = 0;
  833.  
  834.     hsize = 1000L * v->wi_w / width;
  835.     if (hsize > 1000) hsize = 1000;
  836.     else if (hsize < 1) hsize = 1;
  837.  
  838.     vsize = 1000L * v->wi_h / height;
  839.     if (vsize > 1000) vsize = 1000;
  840.     else if (vsize < 1) vsize = 1;
  841.  
  842.     if (width > v->wi_w)
  843.         hpos = 1000L * t->offx / (width - v->wi_w);
  844.     else
  845.         hpos = 1;
  846.  
  847.     if (height > v->wi_h)
  848.         vpos = 1000L * t->offy / (height - v->wi_h);
  849.     else
  850.         vpos = 1;
  851.  
  852.     if (hpos < 1) hpos = 1;
  853.     else if (hpos > 1000) hpos = 1000;
  854.  
  855.     if (vpos < 1) vpos = 1;
  856.     else if (vpos > 1000) vpos = 1000;
  857.  
  858.     if (v->wi_kind & HSLIDE) {
  859.         wind_set(v->wi_handle, WF_HSLIDE, hpos, 0, 0, 0);
  860.         wind_set(v->wi_handle, WF_HSLSIZE, hsize, 0, 0, 0);
  861.     }
  862.     if (v->wi_kind & VSLIDE) {
  863.         wind_set(v->wi_handle, WF_VSLIDE, vpos, 0, 0, 0);
  864.         wind_set(v->wi_handle, WF_VSLSIZE, vsize, 0, 0, 0);
  865.     }
  866. }
  867.  
  868. static void
  869. output_textwin(t, c)
  870.     TEXTWIN *t;
  871.     int c;
  872. {
  873.     c &= 0x00ff;
  874.     if (!c) return;
  875.  
  876.     if (c == '\r') {
  877.         t->cx = 0; return;
  878.     }
  879.     if (c == '\n') {
  880.         t->cx = 0;
  881.         if (t->cy < t->maxy - 1)
  882.             t->cy++;
  883.         return;
  884.     }
  885.     t->data[t->cy][t->cx] = c;
  886.     t->cflag[t->cy][t->cx] = CDIRTY | ((c>='A' && c<='Z') ? CINVERSE : 0)
  887.                     | COLORS(1, 0);
  888.  
  889.     t->dirty[t->cy] |= SOMEDIRTY;
  890.     t->cx++;
  891.     if (t->cx >= t->maxx) {
  892.         if (t->term_flags & FWRAP) {
  893.             t->cx = 0;
  894.             t->cy++;
  895.             if (t->cy >= t->maxy)
  896.                 t->cy = t->maxy - 1;
  897.         } else {
  898.             t->cx = t->maxx - 1;
  899.         }
  900.     }
  901.     refresh_textwin(t);
  902. }
  903.  
  904. /*
  905.  * Create a new text window with title t, w columns, and h rows,
  906.  * and place it at x, y on the screen; the new window should have the
  907.  * set of gadgets specified by "kind", and should provide "s"
  908.  * lines of scrollback.
  909.  */
  910.  
  911. TEXTWIN *
  912. create_textwin(title, x, y, w, h, s, kind)
  913.     char *title;
  914.     int x, y, w, h, s, kind;
  915. {
  916.     WINDOW *v;
  917.     TEXTWIN *t;
  918.     int firstchar, lastchar, distances[5], maxwidth, effects[3];
  919.     int width, height;
  920.     extern int default_height;    /* in main.c */
  921.     int i, j;
  922.  
  923.     extern void normal_putch();
  924.  
  925.     t = malloc(sizeof(TEXTWIN));
  926.     if (!t) return t;
  927.  
  928.     t->maxx = w;
  929.     t->maxy = h+s;
  930.     t->miny = s;
  931.     t->cx = 0;
  932.     t->cy = t->miny;
  933.  
  934. /* we get font data from the VDI */
  935.     set_font(default_font, default_height);
  936.     vqt_fontinfo(vdi_handle, &firstchar, &lastchar, distances, &maxwidth,
  937.              effects);
  938.     t->cfont = default_font;
  939.     t->cpoints = default_height;
  940.     t->cmaxwidth = maxwidth;
  941.     t->cheight = distances[0]+distances[4]+1;
  942.     t->cbase = distances[4];
  943.     t->minADE = firstchar;
  944.     t->maxADE = lastchar;
  945.     t->cwidths = 0;
  946.     set_cwidths(t);
  947.  
  948. /* initialize the window data */
  949.     t->data = malloc(sizeof(char *) * t->maxy);
  950.     t->cflag = malloc(sizeof(short *) * t->maxy);
  951.     t->dirty = malloc((size_t)t->maxy);
  952.  
  953.     if (!t->dirty || !t->cflag || !t->data) return 0;
  954.  
  955.     for (i = 0; i < t->maxy; i++) {
  956.         t->dirty[i] = 0; /* the window starts off clear */
  957.         t->data[i] = malloc((size_t)t->maxx+1);
  958.         t->cflag[i] = malloc(sizeof(short) * (size_t)(t->maxx+1));
  959.         if (!t->cflag[i] || !t->data[i]) return 0;
  960.         for (j = 0; j < t->maxx; j++) {
  961.             t->data[i][j] = ' ';
  962.             t->cflag[i][j] = COLORS(1, 0);
  963.         }
  964.     }
  965.  
  966.     t->scrolled = t->nbytes = t->draw_time = 0;
  967.  
  968. /* calculate max. window size, and initialize the WINDOW struct */
  969.     width = t->maxx * t->cmaxwidth;
  970.     height = h * t->cheight;
  971.     v = create_window(title, kind, x, y, width, height);
  972.     if (!v) {
  973.         free(t);
  974.         return 0;
  975.     }
  976.  
  977.     v->extra = t;
  978.     v->wtype = TEXT_WIN;
  979.     t->win = v;
  980.  
  981. /* initialize all the methods for v */
  982.     v->draw = draw_textwin;
  983.     v->closed = close_textwin;
  984.     v->fulled = full_textwin;
  985.     v->moved = move_textwin;
  986.     v->sized = size_textwin;
  987.     v->arrowed = arrow_textwin;
  988.     v->hslid = hslid_textwin;
  989.     v->vslid = vslid_textwin;
  990.  
  991.     t->offx = 0;
  992.     t->offy = s * t->cheight;
  993.  
  994.     t->output = output_textwin;
  995.     t->term_cattr = COLORS(1, 0);
  996.     t->term_flags = FWRAP;
  997.     t->fd = t->pgrp = 0;
  998.  
  999.     t->prog = t->cmdlin = t->progdir = 0;
  1000.     t->flashtimer = t->flashperiod = 0;
  1001.     return t;
  1002. }
  1003.  
  1004. /*
  1005.  * destroy a text window
  1006.  */
  1007.  
  1008. #include <osbind.h>
  1009. #include <mintbind.h>
  1010. #include <signal.h>
  1011.  
  1012. void
  1013. destroy_textwin(t)
  1014.     TEXTWIN *t;
  1015. {
  1016.     int i;
  1017.  
  1018.     destroy_window(t->win);
  1019.     for (i = 0; i < t->maxy; i++) {
  1020.         free(t->data[i]);
  1021.         free(t->cflag[i]);
  1022.     }
  1023.     if (t->prog) free(t->prog);
  1024.     if (t->cmdlin) free(t->cmdlin);
  1025.     if (t->progdir) free(t->progdir);
  1026.  
  1027.     free(t->cflag);
  1028.     free(t->data);
  1029.     free(t->dirty);
  1030.     if (t->cwidths) free(t->cwidths);
  1031.     free(t);
  1032.  
  1033.     if (t->fd > 0)
  1034.         (void)Fclose(t->fd);
  1035.     if (t->pgrp > 0)
  1036.         (void)Pkill(-t->pgrp, SIGHUP);
  1037. }
  1038.  
  1039. /*
  1040.  * reset a window's font: this involves resizing the window, too
  1041.  */
  1042.  
  1043. void
  1044. textwin_setfont(t, font, points)
  1045.     TEXTWIN *t;
  1046.     int font;
  1047.     int points;
  1048. {
  1049.     extern int win_flourishes;    /* in window.c */
  1050.     WINDOW *w;
  1051.     int firstchar, lastchar, distances[5], maxwidth, effects[3];
  1052.     int width, height;
  1053.     int dummy;
  1054.     int oldflourishes = win_flourishes;
  1055.     int reopen = 0;
  1056.  
  1057.     w = t->win;
  1058.  
  1059.     if (t->cfont == font && t->cpoints == points)
  1060.         return;        /* no real change happens */
  1061.  
  1062.     win_flourishes = 0;    /* no silly effects, thank you */
  1063.     if (w->wi_handle >= 0) {
  1064.         wind_close(w->wi_handle);
  1065.         wind_delete(w->wi_handle);
  1066.         reopen = 1;
  1067.     }
  1068.     w->wi_handle = -1;
  1069.  
  1070.     t->cfont = font;
  1071.     t->cpoints = points;
  1072.     set_font(font, points);
  1073.     vqt_fontinfo(vdi_handle, &firstchar, &lastchar, distances, &maxwidth,
  1074.              effects);
  1075.     t->cmaxwidth = maxwidth;
  1076.     t->cheight = distances[0]+distances[4]+1;
  1077.     t->cbase = distances[4];
  1078.     t->minADE = firstchar;
  1079.     t->maxADE = lastchar;
  1080.     set_cwidths(t);
  1081.  
  1082.     width = NCOLS(t) * t->cmaxwidth;
  1083.     height = NROWS(t) * t->cheight;
  1084.  
  1085.     wind_calc(WC_BORDER, w->wi_kind, w->wi_fullx, w->wi_fully, width,
  1086.         height, &dummy, &dummy, &w->wi_fullw, &w->wi_fullh);
  1087.     if (w->wi_fullw > wdesk) w->wi_fullw = wdesk;
  1088.     if (w->wi_fullh > hdesk) w->wi_fullh = hdesk;
  1089.  
  1090.     if (w->wi_fullx + w->wi_fullw > xdesk + wdesk)
  1091.         w->wi_fullx = xdesk + (wdesk - w->wi_fullw)/2;
  1092.     if (w->wi_fully + w->wi_fullh > ydesk + hdesk)
  1093.         w->wi_fully = ydesk + (hdesk - w->wi_fullh)/2;
  1094.  
  1095.     wind_calc(WC_WORK, w->wi_kind, w->wi_fullx, w->wi_fully, w->wi_fullw, w->wi_fullh,
  1096.         &dummy, &dummy, &width, &height);
  1097.  
  1098.     if (w->wi_w > width) w->wi_w = width;
  1099.     if (w->wi_h > height) w->wi_h = height;
  1100.  
  1101.     if (reopen)
  1102.         open_window(w);
  1103.     win_flourishes = oldflourishes;
  1104. }
  1105.  
  1106. /*
  1107.  * make a text window have a new number of rows and columns, and
  1108.  * a new amount of scrollback
  1109.  */
  1110.  
  1111. void
  1112. resize_textwin(t, cols, rows, scrollback)
  1113.     TEXTWIN *t;
  1114.     int cols, rows, scrollback;
  1115. {
  1116.     extern int win_flourishes;    /* in window.c */
  1117.     WINDOW *w = t->win;
  1118.     int i, j, mincols;
  1119.     int delta;
  1120.     UCHAR **newdata;
  1121.     short **newcflag;
  1122.     char *newdirty;
  1123.     int width, height, dummy;
  1124.     int oldflourishes = win_flourishes;
  1125.     int reopen = 0;
  1126.  
  1127.     if (t->maxx == cols && t->miny == scrollback &&
  1128.         t->maxy == rows+scrollback)
  1129.         return;        /* no change */
  1130.     newdata = malloc(sizeof(char *) * (rows+scrollback));
  1131.     newcflag = malloc(sizeof(short *) * (rows+scrollback));
  1132.     newdirty = malloc((size_t)(rows+scrollback));
  1133.     if (!newdata || !newcflag || !newdirty)
  1134.         return;
  1135.  
  1136.     mincols = (cols < t->maxx) ? cols : t->maxx;
  1137.  
  1138. /* first, initialize the new data to blanks */
  1139.     for (i = 0; i < rows+scrollback; i++) {
  1140.         newdirty[i] = 0;
  1141.         newdata[i] = malloc((size_t)cols+1);
  1142.         newcflag[i] = malloc(sizeof(short)*(cols+1));
  1143.         if (!newcflag[i] || !newdata[i])
  1144.             return;
  1145.         for(j = 0; j < cols; j++) {
  1146.             newdata[i][j] = ' '; newcflag[i][j] = COLORS(1, 0);
  1147.         }
  1148.     }
  1149.  
  1150. /* now, copy as much scrollback as we can */
  1151.  
  1152.     if (rows+scrollback >= t->maxy) {
  1153.         delta = rows+scrollback - t->maxy;
  1154.         for (i = 0; i < t->maxy;i++) {
  1155.             for (j = 0; j < mincols; j++) {
  1156.                 newdata[i+delta][j] = t->data[i][j];
  1157.                 newcflag[i+delta][j] = t->cflag[i][j];
  1158.             }
  1159.         }
  1160.     } else {
  1161.         delta = t->maxy - (rows+scrollback);
  1162.         for (i = 0; i < rows+scrollback; i++) {
  1163.             for (j = 0; j < mincols; j++) {
  1164.                 newdata[i][j] = t->data[i+delta][j];
  1165.                 newcflag[i][j] = t->cflag[i+delta][j];
  1166.             }
  1167.         }
  1168.     }
  1169.  
  1170. /* finally, free the old data and flags */
  1171.     for(i=0; i < t->maxy; i++) {
  1172.         free(t->data[i]); free(t->cflag[i]);
  1173.     }
  1174.     free(t->dirty);
  1175.     free(t->cflag);
  1176.     free(t->data);
  1177.  
  1178.     t->dirty = newdirty;
  1179.     t->cflag = newcflag;
  1180.     t->data = newdata;
  1181.     t->cy = t->cy - SCROLLBACK(t) + scrollback;
  1182.     t->maxx = cols;
  1183.     t->maxy = rows+scrollback;
  1184.     t->miny = scrollback;
  1185.     if (t->cx >= cols) t->cx = 0;
  1186.     if (t->cy >= t->maxy) t->cy = t->maxy-1;
  1187.     if (t->cy < scrollback) t->cy = scrollback;
  1188.     if (t->offy < scrollback * t->cheight)
  1189.         t->offy = scrollback * t->cheight;
  1190.  
  1191.     win_flourishes = 0;
  1192.     if (w->wi_handle >= 0) {
  1193.         wind_close(w->wi_handle);
  1194.         wind_delete(w->wi_handle);
  1195.         reopen = 1;
  1196.     }
  1197.     w->wi_handle = -1;
  1198.  
  1199.     width = t->maxx * t->cmaxwidth;
  1200.     height = rows * t->cheight;
  1201.  
  1202.     wind_calc(WC_BORDER, w->wi_kind, w->wi_fullx, w->wi_fully, width,
  1203.         height, &dummy, &dummy, &w->wi_fullw, &w->wi_fullh);
  1204.     if (w->wi_fullw > wdesk) w->wi_fullw = wdesk;
  1205.     if (w->wi_fullh > hdesk) w->wi_fullh = hdesk;
  1206.  
  1207.     if (w->wi_fullx + w->wi_fullw > xdesk + wdesk)
  1208.         w->wi_fullx = xdesk + (wdesk - w->wi_fullw)/2;
  1209.     if (w->wi_fully + w->wi_fullh > ydesk + hdesk)
  1210.         w->wi_fully = ydesk + (hdesk - w->wi_fullh)/2;
  1211.  
  1212.     wind_calc(WC_WORK, w->wi_kind, w->wi_fullx, w->wi_fully, w->wi_fullw, w->wi_fullh,
  1213.         &dummy, &dummy, &width, &height);
  1214.  
  1215.     if (w->wi_w > width) w->wi_w = width;
  1216.     if (w->wi_h > height) w->wi_h = height;
  1217.  
  1218.     if (reopen)
  1219.         open_window(w);
  1220.     win_flourishes = oldflourishes;
  1221. }
  1222.  
  1223. /* set the "cwidths" array for the given window correctly;
  1224.  * this function may be called ONLY when the font & height are already
  1225.  * set correctly, and only after t->cmaxwidth is set
  1226.  */
  1227.  
  1228. static void
  1229. set_cwidths(t)
  1230.     TEXTWIN *t;
  1231. {
  1232.     int i, status, dummy, wide;
  1233.     int widths[256];
  1234.     int monospaced = 1;
  1235.     int dfltwide;
  1236.  
  1237.     if (t->cwidths) {
  1238.         free(t->cwidths);
  1239.         t->cwidths = 0;
  1240.     }
  1241.     vqt_width(vdi_handle, DEFAULT_CHAR, &dfltwide, &dummy, &dummy);
  1242.  
  1243.     for (i = 0; i < 255; i++) {
  1244.         status = vqt_width(vdi_handle, i, &wide, &dummy, &dummy);
  1245.         if (status == -1) wide = dfltwide;
  1246.         if (wide != t->cmaxwidth)
  1247.             monospaced = 0;
  1248.         widths[i] = wide;
  1249.     }
  1250.     if (!monospaced) {
  1251.         t->cwidths = malloc(256 * sizeof(short));
  1252.         if (!t->cwidths) return;
  1253.         for (i = 0; i < 255; i++)
  1254.             t->cwidths[i] = widths[i];
  1255.     }
  1256. }
  1257.