home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / window.c < prev    next >
C/C++ Source or Header  |  1998-09-19  |  27KB  |  1,130 lines

  1. /*
  2.  * Window management. Some of the functions are internal, and some are
  3.  * attached to keys that the user actually types.
  4.  *
  5.  * $Header: /usr/build/vile/vile/RCS/window.c,v 1.85 1998/09/19 22:52:06 kev Exp $
  6.  *
  7.  */
  8.  
  9. #include        "estruct.h"
  10. #include    "edef.h"
  11.  
  12. /*
  13.  * Unlink the given window-pointer from the list
  14.  */
  15. static void
  16. unlink_window(WINDOW *thewp)
  17. {
  18.     register WINDOW *p, *q;
  19.  
  20.     for (p = wheadp, q = 0; p != 0; q = p, p = p->w_wndp)
  21.         if (p == thewp) {
  22.             if (q != 0)
  23.                 q->w_wndp = p->w_wndp;
  24.             else
  25.                 wheadp = p->w_wndp;
  26.             break;
  27.         }
  28. }
  29.  
  30. /*
  31.  * Set the current window (and associated current buffer).
  32.  */
  33. int
  34. set_curwp (WINDOW *wp)
  35. {
  36.     if (wp == curwp)
  37.         return (TRUE);
  38.     curwp = wp;
  39. #if !WINMARK
  40.     /* FIXME: this wouldn't be necessary if MK were stored per-buffer */
  41.     MK = nullmark;
  42. #endif
  43.     make_current(curwp->w_bufp);
  44.     upmode();
  45.     updatelistbuffers();
  46.     return (TRUE);
  47. }
  48.  
  49. /*
  50.  * Adjust a LINEPTR forward by the given number of screen-rows, limited by
  51.  * the end of the buffer.
  52.  */
  53. static LINEPTR
  54. adjust_forw(WINDOW *wp, LINEPTR lp, int n)
  55. {
  56.     register int i;
  57.     LINEPTR    dlp;
  58.     for (i = n; i > 0 && (lp != win_head(wp)); ) {
  59.         if ((i -= line_height(wp, lp)) < 0)
  60.             break;
  61.         dlp = lforw(lp);
  62.         if (dlp == win_head(wp))
  63.             break;
  64.         lp = dlp;
  65.     }
  66.     return lp;
  67. }
  68.  
  69. /*
  70.  * Adjust a LINEPTR backward by the given number of screen-rows, limited by
  71.  * the end of the buffer.
  72.  */
  73. static LINEPTR
  74. adjust_back(WINDOW *wp, LINEPTR lp, int n)
  75. {
  76.     register int i;
  77.     LINEPTR    dlp;
  78.     for (i = n; i > 0 && (lp != win_head(wp)); ) {
  79.         if ((i -= line_height(wp, lp)) < 0)
  80.             break;
  81.         dlp = lback(lp);
  82.         if (dlp == win_head(wp))
  83.             break;
  84.         lp = dlp;
  85.     }
  86.     return lp;
  87. }
  88.  
  89. /*
  90.  * Reposition dot's line to line "n" of the window. If the argument is
  91.  * positive, it is that line. If it is negative it is that line from the
  92.  * bottom. If it is 0 the window is centered around dot (this is what
  93.  * the standard redisplay code does). Defaults to 0.
  94.  */
  95. int
  96. reposition(int f, int n)
  97. {
  98.     if (f) {
  99.         int an;
  100.         /* clamp the value at the size of the window */
  101.         an = absol(n);
  102.         if (an > curwp->w_ntrows)
  103.             curwp->w_force = curwp->w_ntrows * (n / an);
  104.         else
  105.             curwp->w_force = n;
  106.         curwp->w_flag |= WFFORCE;
  107.     }
  108.     return update(TRUE);
  109. }
  110.  
  111. /*
  112.  * Refresh the screen. With no argument, it just does the refresh. With an
  113.  * argument it recenters "." in the current window.
  114.  */
  115. /* ARGSUSED */
  116. int
  117. vile_refresh(int f, int n GCC_UNUSED)
  118. {
  119.  
  120.     if (f == FALSE) {
  121.         sgarbf = TRUE;
  122.     } else {
  123.             curwp->w_force = 0;             /* Center dot. */
  124.             curwp->w_flag |= WFFORCE;
  125.     }
  126.  
  127.     return (TRUE);
  128. }
  129.  
  130. /*
  131.  * The command make the next window (next => down the screen) the current
  132.  * window. There are no real errors, although the command does nothing if
  133.  * there is only 1 window on the screen.
  134.  *
  135.  * with an argument this command finds the <n>th window from the top
  136.  *
  137.  */
  138. int
  139. nextwind(int f, int n)
  140. {
  141.     register WINDOW *wp;
  142.     register int nwindows;        /* total number of windows */
  143.  
  144.     if (f) {
  145.  
  146.         /* first count the # of windows */
  147.         nwindows = 0;
  148.         for_each_visible_window(wp)
  149.             nwindows++;
  150.  
  151.         /* if the argument is negative, it is the nth window
  152.            from the bottom of the screen            */
  153.         if (n < 0)
  154.             n = nwindows + n + 1;
  155.  
  156.         /* if an argument, give them that window from the top */
  157.         if (n > 0 && n <= nwindows) {
  158.             wp = wheadp;
  159.             while (--n)
  160.                 wp = wp->w_wndp;
  161.         } else {
  162.             mlforce("[Window number out of range]");
  163.             return(FALSE);
  164.         }
  165.     } else {
  166.         if ((wp = curwp->w_wndp) == NULL)
  167.             wp = wheadp;
  168.     }
  169.     return set_curwp(wp);
  170. }
  171.  
  172. int
  173. poswind(int f, int n)
  174. {
  175.     register int c;
  176.     register int row;
  177.     int s;
  178.  
  179.     if (!f)
  180.         n = 1;
  181.  
  182.     if (clexec || isnamedcmd) {
  183.         static char cbuf[20];
  184.         if ((s=mlreply("Position window with cursor at:  ", cbuf,
  185.                         20)) != TRUE)
  186.             return s;
  187.         c = cbuf[0];
  188.     } else {
  189.         c = keystroke();
  190.         if (ABORTED(c))
  191.             return ABORT;
  192.     }
  193.  
  194.     if (strchr("+hHtT\r", c)) {
  195.         row = n;
  196.     } else if (strchr(".mM", c)) {
  197.         row = 0;
  198.     } else if (strchr("-lLbB\r", c)) {
  199.         row = -n;
  200.     } else {
  201.         if (!(clexec || isnamedcmd))
  202.             kbd_alarm();
  203.         return FALSE;
  204.     }
  205.  
  206.     return(reposition(TRUE,row));
  207. }
  208.  
  209. /*
  210.  * This command makes the previous window (previous => up the screen) the
  211.  * current window. There aren't any errors, although the command does not do a
  212.  * lot if there is 1 window.
  213.  */
  214. int
  215. prevwind(int f, int n)
  216. {
  217.     register WINDOW *wp1;
  218.     register WINDOW *wp2;
  219.  
  220.     /* if we have an argument, we mean the nth window from the bottom */
  221.     if (f)
  222.         return(nextwind(f, -n));
  223.  
  224.     wp1 = wheadp;
  225.     wp2 = curwp;
  226.  
  227.     if (wp1 == wp2)
  228.         wp2 = NULL;
  229.  
  230.     while (wp1->w_wndp != wp2)
  231.         wp1 = wp1->w_wndp;
  232.  
  233.     return set_curwp(wp1);
  234. }
  235.  
  236. /*
  237.  * This command moves the current window down by "arg" lines. Recompute the
  238.  * top line in the window. The move up and move down code is almost completely
  239.  * the same; most of the work has to do with reframing the window, and picking
  240.  * a new dot. We share the code by having "move down" just be an interface to
  241.  * "move up". Magic.
  242.  */
  243. int
  244. mvdnwind(int f, int n)
  245. {
  246.     if (!f)
  247.         n = 1;
  248.     return (mvupwind(TRUE, -n));
  249. }
  250.  
  251. /*
  252.  * Move the current window up by "arg" lines. Recompute the new top line of
  253.  * the window. Look to see if "." is still on the screen. If it is, you win.
  254.  * If it isn't, then move "." to center it in the new framing of the window
  255.  * (this command does not really move "." (except as above); it moves the
  256.  * frame).
  257.  */
  258. int
  259. mvupwind(int f, int n)
  260. {
  261.     register LINE  *lp;
  262.     register int    i;
  263.     int             was_n = n;
  264.  
  265.     lp = curwp->w_line.l;
  266.  
  267.     if (!f)
  268.         n = 1;
  269.  
  270.     if (n < 0)
  271.         curwp->w_flag |= WFKILLS;
  272.     else
  273.         curwp->w_flag |= WFINS;
  274.  
  275.     if (n < 0) {
  276.         while (n++ && lforw(lp) != buf_head(curbp))
  277.             lp = lforw(lp);
  278.     } else {
  279.         while (n-- && lback(lp) != buf_head(curbp))
  280.             lp = lback(lp);
  281.     }
  282.  
  283.     curwp->w_line.l = lp;
  284.     curwp->w_line.o = 0;
  285.     curwp->w_flag |= WFHARD | WFMODE;
  286.  
  287.     /* is it still in the window */
  288.     for (i = 0; i < curwp->w_ntrows; lp = lforw(lp)) {
  289.         if ((i += line_height(curwp,lp)) > curwp->w_ntrows)
  290.             break;
  291.         if (lp == DOT.l)
  292.             return (TRUE);
  293.         if (lforw(lp) == buf_head(curbp))
  294.             break;
  295.     }
  296.     /*
  297.      * now lp is either just past the window bottom, or it's the last
  298.      * line of the file
  299.      */
  300.  
  301.     /* preserve the current column */
  302.     if (curgoal < 0)
  303.         curgoal = getccol(FALSE);
  304.  
  305.     if (was_n < 0)
  306.         DOT.l = curwp->w_line.l;
  307.     else
  308.         DOT.l = lback(lp);
  309.     DOT.o = getgoal(DOT.l);
  310.     return (TRUE);
  311. }
  312.  
  313. int
  314. mvdnnxtwind(int f, int n)
  315. {
  316.     int    status;
  317.  
  318.     (void)nextwind(FALSE, 1);
  319.     status = mvdnwind(f, n);
  320.     (void)prevwind(FALSE, 1);
  321.     return status;
  322. }
  323.  
  324. int
  325. mvupnxtwind(int f, int n)
  326. {
  327.     int    status;
  328.  
  329.     (void)nextwind(FALSE, 1);
  330.     status = mvupwind(f, n);
  331.     (void)prevwind(FALSE, 1);
  332.     return status;
  333. }
  334.  
  335. static int
  336. scroll_sideways(int f, int n)
  337. {
  338.     int    original = w_val(curwp,WVAL_SIDEWAYS);
  339.  
  340.     if (!f) {
  341.         int    nominal = term.t_ncol / 2;
  342.         n = (n > 0) ? nominal : -nominal;
  343.     }
  344.  
  345.     make_local_w_val(curwp,WVAL_SIDEWAYS);
  346.     w_val(curwp, WVAL_SIDEWAYS) += n;
  347.  
  348.     if (w_val(curwp, WVAL_SIDEWAYS) < 0) {
  349.         if (original == 0)
  350.             kbd_alarm();
  351.         w_val(curwp, WVAL_SIDEWAYS) = 0;
  352.     }
  353.  
  354.     if (original != w_val(curwp,WVAL_SIDEWAYS))
  355.             curwp->w_flag  |= WFHARD|WFMOVE|WFMODE;
  356.  
  357.     return TRUE;
  358. }
  359.  
  360. int
  361. mvrightwind(int f, int n)
  362. {
  363.     return scroll_sideways(f,n);
  364. }
  365.  
  366. int
  367. mvleftwind(int f, int n)
  368. {
  369.     return scroll_sideways(f,-n);
  370. }
  371.  
  372. /*
  373.  * This command makes the current window the only window on the screen.
  374.  * Try to set the framing so that "." does not have to move on the
  375.  * display. Some care has to be taken to keep the values of dot and mark in
  376.  * the buffer structures right if the distruction of a window makes a buffer
  377.  * become undisplayed.
  378.  */
  379. /* ARGSUSED */
  380. int
  381. onlywind(int f GCC_UNUSED, int n GCC_UNUSED)
  382. {
  383.         register WINDOW *wp;
  384.  
  385.         wp = wheadp;
  386.         while (wp != NULL) {
  387.         register WINDOW *nwp;
  388.         nwp = wp->w_wndp;
  389.             if (wp != curwp) {
  390.                     if (--wp->w_bufp->b_nwnd == 0)
  391.                             undispbuff(wp->w_bufp,wp);
  392.             unlink_window(wp);
  393.                     free((char *) wp);
  394.             }
  395.                 wp = nwp;
  396.         }
  397.         wheadp = curwp;
  398.         wheadp->w_wndp = NULL;
  399.  
  400.         curwp->w_line.l = adjust_back(curwp, curwp->w_line.l, curwp->w_toprow);
  401.     curwp->w_line.o = 0;
  402.         curwp->w_ntrows = term.t_nrow-2;
  403.         curwp->w_toprow = 0;
  404.         curwp->w_flag  |= WFMODE|WFHARD|WFSBAR;
  405.     curwp->w_split_hist = 0;
  406.         return (TRUE);
  407. }
  408.  
  409. /*
  410.  * Delete the current window
  411.  */
  412.  
  413. /* ARGSUSED */
  414. int
  415. delwind(int f GCC_UNUSED, int n GCC_UNUSED)
  416. {
  417.     return delwp(curwp);
  418. }
  419.  
  420. /*
  421.  * We attach to each window structure another field (an unsigned long)
  422.  * which I called w_split_history.  When we split a window, we shift this
  423.  * field left by one bit.  The least significant bit for the upper window
  424.  * is 0, the bottom window's lsb is set to 1.
  425.  *
  426.  * We examine the lsb when deleting windows to decide whether to give up
  427.  * the space for the deleted window to the upper window or lower window.
  428.  * If the lsb is 0, we give it to the lower window.  If it is 1 we give it
  429.  * to the upper window.  If the lsb of the receiving window is different
  430.  * from that of the window being deleted, this means that the two match and
  431.  * so the history is shifted right by one bit for the receiving window.
  432.  * Otherwise we leave the history alone.
  433.  *                            kev, 2/94
  434.  *
  435.  * Example:
  436.  *
  437.  * |    |       | 00    | 00    | 00    | 00
  438.  * |    | 0     -       -       -       -
  439.  * |    |       | 01    | 01    | 01    | 01
  440.  * | 0 -->      -   --> -   --> -   --> -   --> |
  441.  * |    |       |       | 10    |       |
  442.  * |    | 1     | 1     -       | 1     |
  443.  * |    |       |       | 11    |       |
  444.  *
  445.  * Full Split   Split   and     Kill    Kill
  446.  * Screen               Again   Again   either  1
  447.  *                              10 or
  448.  *                              11
  449.  */
  450.  
  451. int
  452. delwp(WINDOW *thewp)
  453. {
  454.     register WINDOW *wp;    /* window to receive deleted space */
  455.     int visible = is_visible_window(thewp);
  456.  
  457.     /* if there is only one window, don't delete it */
  458.     if (wheadp->w_wndp == NULL) {
  459.         mlforce("[Cannot delete the only window]");
  460.         return(FALSE);
  461.     }
  462.  
  463.     /* find receiving window and give up our space */
  464.     if (thewp == wheadp
  465.      || ((thewp->w_split_hist & 1) == 0 && thewp->w_wndp)
  466.      || !visible) {
  467.         /* merge with next window down */
  468.         wp = thewp->w_wndp;
  469.         if (visible) {
  470.             wp->w_line.l = adjust_back(wp, wp->w_line.l,
  471.                             thewp->w_ntrows+1);
  472.             wp->w_line.o = 0;
  473.             wp->w_ntrows += thewp->w_ntrows+1;
  474.             wp->w_toprow = thewp->w_toprow;
  475.             if (wp->w_split_hist & 1)
  476.                 wp->w_split_hist >>= 1;
  477.         }
  478.         if (thewp == wheadp)
  479.             wheadp = wp;
  480.         else {
  481.             WINDOW *pwp = wheadp;
  482.             while(pwp->w_wndp != thewp)
  483.                 pwp = pwp->w_wndp;
  484.             pwp->w_wndp = wp;
  485.         }
  486.     } else {
  487.         /* find window before thewp in linked list */
  488.         wp = wheadp;
  489.         while(wp->w_wndp != thewp)
  490.             wp = wp->w_wndp;
  491.         /* add thewp's rows to the next window up */
  492.         wp->w_ntrows += thewp->w_ntrows+1;
  493.  
  494.         wp->w_wndp = thewp->w_wndp; /* make their next window ours */
  495.         if ((wp->w_split_hist & 1) == 0)
  496.             wp->w_split_hist >>= 1;
  497.     }
  498.  
  499.     /* get rid of the current window */
  500.     if (visible && --thewp->w_bufp->b_nwnd == 0)
  501.         undispbuff(thewp->w_bufp,thewp);
  502.     if (thewp == curwp) {
  503.         curwp = wp;
  504.         make_current(curwp->w_bufp);
  505.     }
  506.     free((char *)thewp);
  507.     if (visible) {
  508.         upmode();
  509.         wp->w_flag |= WFSBAR | WFHARD;
  510.     }
  511.     return(TRUE);
  512. }
  513.  
  514. /*
  515.  * Copy the window-traits struct, and adjust the embedded VAL struct so that
  516.  * modes that are local remain so.
  517.  */
  518. void
  519. copy_traits(W_TRAITS *dst, W_TRAITS *src)
  520. {
  521.     *dst = *src;
  522.     copy_mvals(NUM_W_VALUES, dst->w_vals.wv, src->w_vals.wv);
  523. }
  524.  
  525. /*
  526.     Split the current window.  A window smaller than 3 lines cannot be
  527.     split.  An argument of 1 forces the cursor into the upper window, an
  528.     argument of two forces the cursor to the lower window.  The only other
  529.     error that is possible is a "malloc" failure allocating the structure
  530.     for the new window.
  531.  */
  532. static WINDOW *
  533. splitw(int f, int n)
  534. {
  535.         register WINDOW *wp;
  536.         register LINE   *lp;
  537.         register int    ntru;
  538.         register int    ntrl;
  539.         register int    ntrd;
  540.         register WINDOW *wp1;
  541.         register WINDOW *wp2;
  542.  
  543.         if (curwp->w_ntrows < MINWLNS) {
  544.                 mlforce("[Cannot split a %d line window]", curwp->w_ntrows);
  545.                 return NULL;
  546.         }
  547.     /* set everything to 0's unless we want nonzero */
  548.         if ((wp = typecalloc(WINDOW)) == NULL) {
  549.         (void)no_memory("WINDOW");
  550.                 return NULL;
  551.         }
  552.     ++curwp->w_bufp->b_nwnd;           /* Displayed twice.     */
  553.         wp->w_bufp  = curwp->w_bufp;
  554.         copy_traits(&(wp->w_traits), &(curwp->w_traits));
  555.         ntru = (curwp->w_ntrows-1) / 2;         /* Upper size           */
  556.         ntrl = (curwp->w_ntrows-1) - ntru;      /* Lower size           */
  557.  
  558.         lp = curwp->w_line.l;
  559.         ntrd = 0;
  560.         while (lp != DOT.l) {
  561.                 ntrd += line_height(wp,lp);
  562.                 lp = lforw(lp);
  563.         }
  564.  
  565.     /* ntrd is now the row containing dot */
  566.         if (((f == FALSE) && (ntrd <= ntru)) || ((f == TRUE) && (n == 1))) {
  567.                 /* Old is upper window. */
  568.             /* Adjust the top line if necessary */
  569.                 if (ntrd == ntru) {             /* Hit mode line.       */
  570.             if (ntrl > 1) {
  571.                 ntru++;
  572.                 ntrl--;
  573.             } else {
  574.                             curwp->w_line.l = lforw(curwp->w_line.l);
  575.                 curwp->w_line.o = 0;
  576.             }
  577.         }
  578.                 curwp->w_ntrows = ntru; /* new size */
  579.         /* insert new window after curwp in window list */
  580.                 wp->w_wndp = curwp->w_wndp;
  581.                 curwp->w_wndp = wp;
  582.         /* set new window's position and size */
  583.                 wp->w_toprow = curwp->w_toprow+ntru+1;
  584.                 wp->w_ntrows = ntrl;
  585.         /* try to keep lower from reframing */
  586.         wp->w_line.l = adjust_forw(wp, wp->w_line.l, ntru+1);
  587.         wp->w_line.o = 0;
  588.         wp->w_dot.l = wp->w_line.l;
  589.         wp->w_dot.o = 0;
  590.         /* update the split history */
  591.         curwp->w_split_hist <<= 1;
  592.         wp->w_split_hist = curwp->w_split_hist | 1;
  593.         } else {
  594.         /* Old is lower window  */
  595.                 wp1 = NULL;
  596.                 wp2 = wheadp;
  597.                 while (wp2 != curwp) {
  598.                         wp1 = wp2;
  599.                         wp2 = wp2->w_wndp;
  600.                 }
  601.                 if (wp1 == NULL)
  602.                         wheadp = wp;
  603.                 else
  604.                         wp1->w_wndp = wp;
  605.                 wp->w_wndp   = curwp;
  606.                 wp->w_toprow = curwp->w_toprow;
  607.                 wp->w_ntrows = ntru;
  608.                 ++ntru;                         /* Mode line.           */
  609.                 curwp->w_toprow += ntru;
  610.                 curwp->w_ntrows  = ntrl;
  611.         wp->w_dot.l = wp->w_line.l;
  612.         /* move upper window dot to bottom line of upper */
  613.         wp->w_dot.l = adjust_forw(wp, wp->w_dot.l, ntru-2);
  614.         wp->w_dot.o = 0;
  615.         /* adjust lower window topline */
  616.         curwp->w_line.l = adjust_forw(curwp, curwp->w_line.l, ntru);
  617.         curwp->w_line.o = 0;
  618.         /* update the split history */
  619.         wp->w_split_hist <<= 1;
  620.         curwp->w_split_hist = wp->w_split_hist | 1;
  621.         }
  622.         curwp->w_flag |= WFMODE|WFHARD|WFSBAR;
  623.         wp->w_flag |= WFMODE|WFHARD;
  624.         return wp;
  625. }
  626.  
  627. /* external callable version -- return int instead of (WINDOW *) */
  628. int
  629. splitwind(int f, int n)
  630. {
  631.     return (splitw(f,n)) ? TRUE:FALSE;
  632. }
  633.  
  634. /*
  635.  * Enlarge the current window. Find the window that loses space. Make sure it
  636.  * is big enough. If so, hack the window descriptions, and ask redisplay to do
  637.  * all the hard work. You don't just set "force reframe" because dot would
  638.  * move.
  639.  */
  640. int
  641. enlargewind(int f, int n)
  642. {
  643.         register WINDOW *adjwp;
  644.  
  645.         if (n < 0)
  646.                 return (shrinkwind(f, -n));
  647.         if (wheadp->w_wndp == NULL) {
  648.                 mlforce("[Only one window]");
  649.                 return (FALSE);
  650.         }
  651.         if ((adjwp=curwp->w_wndp) == NULL) {
  652.                 adjwp = wheadp;
  653.                 while (adjwp->w_wndp != curwp)
  654.                         adjwp = adjwp->w_wndp;
  655.         }
  656.         if (adjwp->w_ntrows <= n) {
  657.                 mlforce("[Impossible change]");
  658.                 return (FALSE);
  659.         }
  660.         if (curwp->w_wndp == adjwp) {           /* Shrink below.        */
  661.                 adjwp->w_line.l  = adjust_forw(adjwp, adjwp->w_line.l, n);
  662.         adjwp->w_line.o  = 0;
  663.                 adjwp->w_toprow += n;
  664.         } else {                                /* Shrink above.        */
  665.                 curwp->w_line.l  = adjust_back(curwp, curwp->w_line.l, n);
  666.         curwp->w_line.o  = 0;
  667.                 curwp->w_toprow -= n;
  668.         }
  669.         curwp->w_ntrows += n;
  670.         adjwp->w_ntrows -= n;
  671.         curwp->w_flag |= WFMODE|WFHARD|WFINS|WFSBAR;
  672.         adjwp->w_flag |= WFMODE|WFHARD|WFKILLS;
  673.         return (TRUE);
  674. }
  675.  
  676. /*
  677.  * Shrink the current window. Find the window that gains space. Hack at the
  678.  * window descriptions. Ask the redisplay to do all the hard work.
  679.  */
  680. int
  681. shrinkwind(int f, int n)
  682. {
  683.         register WINDOW *adjwp;
  684.  
  685.         if (n < 0)
  686.                 return (enlargewind(f, -n));
  687.         if (wheadp->w_wndp == NULL) {
  688.                 mlforce("[Only one window]");
  689.                 return (FALSE);
  690.         }
  691.         if ((adjwp=curwp->w_wndp) == NULL) {
  692.                 adjwp = wheadp;
  693.                 while (adjwp->w_wndp != curwp)
  694.                         adjwp = adjwp->w_wndp;
  695.         }
  696.         if (curwp->w_ntrows <= n) {
  697.                 mlforce("[Impossible change]");
  698.                 return (FALSE);
  699.         }
  700.         if (curwp->w_wndp == adjwp) {           /* Grow below.          */
  701.                 adjwp->w_line.l  = adjust_back(adjwp, adjwp->w_line.l, n);
  702.         adjwp->w_line.o  = 0;
  703.                 adjwp->w_toprow -= n;
  704.         } else {                                /* Grow above.          */
  705.                 curwp->w_line.l  = adjust_forw(curwp, curwp->w_line.l, n);
  706.         curwp->w_line.o  = 0;
  707.                 curwp->w_toprow += n;
  708.         }
  709.         curwp->w_ntrows -= n;
  710.         adjwp->w_ntrows += n;
  711.         curwp->w_flag |= WFMODE|WFHARD|WFKILLS|WFSBAR;
  712.         adjwp->w_flag |= WFMODE|WFHARD|WFINS;
  713.         return (TRUE);
  714. }
  715.  
  716. /*    Resize the current window to the requested size    */
  717. int
  718. resize(int f, int n)
  719. {
  720.     int clines;    /* current # of lines in window */
  721.  
  722.     /* must have a non-default argument, else ignore call */
  723.     if (f == FALSE)
  724.         return(TRUE);
  725.  
  726.     /* find out what to do */
  727.     clines = curwp->w_ntrows;
  728.  
  729.     /* already the right size? */
  730.     if (clines == n)
  731.         return(TRUE);
  732.  
  733.     return(enlargewind(TRUE, n - clines));
  734. }
  735.  
  736. /*
  737.  * Pick a window for a pop-up. Split the screen if there is only one window.
  738.  * Pick the uppermost window that isn't the current window. An LRU algorithm
  739.  * might be better. Return a pointer, or NULL on error.
  740.  */
  741. WINDOW  *
  742. wpopup(void)
  743. {
  744.         register WINDOW *wp;
  745.         register WINDOW *owp;
  746.         register WINDOW *biggest_wp;
  747.  
  748.     owp = curwp;
  749.         wp = biggest_wp = wheadp;                /* Find window to split   */
  750.         while (wp->w_wndp != NULL) {
  751.                 wp = wp->w_wndp;
  752.         if(wp->w_ntrows > biggest_wp->w_ntrows)
  753.             biggest_wp = wp;
  754.     }
  755.     if (biggest_wp->w_ntrows >= MINWLNS) {
  756.         curwp = biggest_wp;
  757.         wp = splitw(FALSE,0); /* yes -- choose the unoccupied half */
  758.         curwp = owp;
  759.     }
  760.     else {
  761.         /*  biggest_wp was too small  */
  762.         wp = wheadp;        /* Find window to use    */
  763.             while (wp!=NULL && wp==curwp) /* uppermost non-current window */
  764.                     wp = wp->w_wndp;
  765.         if (wp == NULL)
  766.             wp = wheadp;
  767.     }
  768.         return wp;
  769. }
  770.  
  771. /*
  772.  * Shrink or expand current window to the number of lines in the buffer.
  773.  * If the buffer is too large, make the window as large as possible using
  774.  * space from window closest in the split history.
  775.  */
  776.  
  777. void
  778. shrinkwrap(void)
  779. {
  780.     L_NUM nlines;
  781.  
  782.     if (wheadp->w_wndp == NULL)
  783.     return;            /* only one window */
  784.  
  785.     nlines = line_count(curwp->w_bufp);
  786.     if (nlines <= 0)
  787.     nlines = 1;
  788.  
  789.     if (nlines == curwp->w_ntrows)
  790.     return;
  791.  
  792.     if ((curwp->w_split_hist & 1) == 0 || wheadp == curwp) {
  793.     int nrows, snrows;
  794.     /* give/steal from lower window */
  795.     nrows = curwp->w_ntrows + curwp->w_wndp->w_ntrows - 1;
  796.     /* don't take more than 3/4 of its rows */
  797.     snrows = (nrows*3)/4;
  798.     if (nlines > snrows)
  799.         nlines = snrows;
  800.     resize(TRUE, nlines);
  801.     }
  802.     else {
  803.     /* give/steal from upper window; need to find upper window */
  804.     register WINDOW *wp;
  805.     WINDOW *savewp = curwp;
  806.     int nrows, snrows;
  807.     for (wp = wheadp;
  808.          wp->w_wndp != curwp && wp->w_wndp != NULL;
  809.          wp = wp->w_wndp)
  810.         ;
  811.     curwp = wp;
  812.     nrows = curwp->w_ntrows + curwp->w_wndp->w_ntrows - 1;
  813.     /* don't take more than 3/4 of its rows */
  814.     snrows = (nrows*3)/4;
  815.     if (nlines > snrows)
  816.         nlines = snrows;
  817.     resize(TRUE, nrows - nlines + 1);
  818.     curwp = savewp;
  819.     }
  820. }
  821.  
  822. int
  823. scrnextup(int f, int n)    /* scroll the next window up (back) a page */
  824. {
  825.     int    status;
  826.  
  827.     (void)nextwind(FALSE, 1);
  828.     status = backhpage(f, n);
  829.     (void)prevwind(FALSE, 1);
  830.     return status;
  831. }
  832.  
  833. int
  834. scrnextdw(int f, int n)    /* scroll the next window down (forward) a page */
  835. {
  836.     int    status;
  837.  
  838.     (void)nextwind(FALSE, 1);
  839.     status = forwhpage(f, n);
  840.     (void)prevwind(FALSE, 1);
  841.     return status;
  842. }
  843.  
  844. #if ! SMALLER
  845. /* ARGSUSED */
  846. int
  847. savewnd(int f GCC_UNUSED, int n GCC_UNUSED)    /* save ptr to current window */
  848. {
  849.     swindow = curwp;
  850.     return(TRUE);
  851. }
  852.  
  853. /* ARGSUSED */
  854. int
  855. restwnd(int f GCC_UNUSED, int n GCC_UNUSED)    /* restore the saved screen */
  856. {
  857.     register WINDOW *wp;
  858.  
  859.     /* find the window */
  860.     for_each_visible_window(wp) {
  861.         if (wp == swindow)
  862.             return set_curwp(wp);
  863.     }
  864.  
  865.     mlforce("[No such window exists]");
  866.     return(FALSE);
  867. }
  868. #endif
  869.  
  870. int
  871. newlength(int f, int n)    /* resize the screen, re-writing the screen */
  872. {
  873.     WINDOW *wp;    /* current window being examined */
  874.     WINDOW *nextwp;    /* next window to scan */
  875.     WINDOW *lastwp;    /* last window scanned */
  876.  
  877.     if (!f) {
  878.         mlforce("[No length given]");
  879.         return FALSE;
  880.     }
  881.  
  882.     /* make sure it's in range */
  883.     if (n < MINWLNS || n > term.t_mrow) {
  884.         mlforce("[Screen length out of range]");
  885.         return(FALSE);
  886.     }
  887.  
  888.     if (term.t_nrow == n) {
  889.         return(TRUE);
  890.     } else if (wheadp != 0 && term.t_nrow < n) {
  891.  
  892.         /* go to the last window */
  893.         wp = wheadp;
  894.         while (wp->w_wndp != NULL)
  895.             wp = wp->w_wndp;
  896.  
  897.         /* and enlarge it as needed */
  898.         wp->w_ntrows = n - wp->w_toprow - 2;
  899.         wp->w_flag |= WFHARD|WFMODE;
  900.  
  901.     } else {
  902.  
  903.         /* rebuild the window structure */
  904.         nextwp = wheadp;
  905.         lastwp = NULL;
  906.         while (nextwp != NULL) {
  907.             wp = nextwp;
  908.             nextwp = wp->w_wndp;
  909.  
  910.             /* get rid of it if it is too low */
  911.             if (wp->w_toprow >= n - 2) {
  912.  
  913.                 if (--wp->w_bufp->b_nwnd == 0) {
  914.                     undispbuff(wp->w_bufp,wp);
  915.                 }
  916.  
  917.                 /* update curwp and lastwp if needed */
  918.                 if (wp == curwp) {
  919.                     curwp = wheadp;
  920.                     make_current(curwp->w_bufp);
  921.                 }
  922.                 if (lastwp != NULL)
  923.                     lastwp->w_wndp = NULL;
  924.  
  925.                 /* free the structure */
  926.                 free((char *)wp);
  927.                 wp = NULL;
  928.  
  929.             } else {
  930.                 /* need to change this window size? */
  931.                 if (mode_row(wp) >= n - 3) {
  932.                     wp->w_ntrows = n - wp->w_toprow - 2;
  933.                     wp->w_flag |= WFHARD|WFMODE;
  934.                 }
  935.             }
  936.  
  937.             lastwp = wp;
  938.         }
  939.     }
  940.  
  941.     /* screen is garbage */
  942.     term.t_nrow = n;
  943.     sgarbf = TRUE;
  944.     return(TRUE);
  945. }
  946.  
  947. int
  948. newwidth(int f, int n)    /* resize the screen, re-writing the screen */
  949. {
  950.     register WINDOW *wp;
  951.  
  952.     if (!f) {
  953.         mlforce("[No width given]");
  954.         return FALSE;
  955.     }
  956.  
  957.     /* make sure it's in range */
  958.     if (n < 10 || n > term.t_mcol) {
  959.         mlforce("[Screen width out of range]");
  960.         return(FALSE);
  961.     }
  962.  
  963.     /* otherwise, just re-width it (no big deal) */
  964.     term.t_ncol = n;
  965.     term.t_margin = n / 10;
  966.     term.t_scrsiz = n - (term.t_margin * 2);
  967.  
  968.     /* force all windows to redraw */
  969.     for_each_visible_window(wp)
  970.         wp->w_flag |= WFHARD | WFMOVE | WFMODE;
  971.  
  972.     sgarbf = TRUE;
  973.  
  974.     return(TRUE);
  975. }
  976.  
  977. #if OPT_EVAL
  978. int
  979. getwpos(void)    /* get screen offset of current line in current window */
  980. {
  981.     register int sline;    /* screen line from top of window */
  982.     register LINE *lp;    /* scannile line pointer */
  983.  
  984.     /* search down the line we want */
  985.     lp = curwp->w_line.l;
  986.     sline = 1;
  987.     while (lp != DOT.l) {
  988.         sline += line_height(curwp,lp);
  989.         lp = lforw(lp);
  990.     }
  991.  
  992.     /* and return the value */
  993.     return(sline);
  994. }
  995. #endif
  996.  
  997. /*
  998.  * Initialize all of the windows.
  999.  */
  1000. void
  1001. winit(int screen)
  1002. {
  1003.         register WINDOW *wp;
  1004.  
  1005.         wp = typecalloc(WINDOW);        /* First window         */
  1006.         if (wp==NULL)
  1007.         ExitProgram(BADEXIT);
  1008.         wheadp = wp;
  1009.         curwp  = wp;
  1010.         wp->w_wndp  = NULL;                     /* Initialize window    */
  1011.         wp->w_dot  = nullmark;
  1012.     wp->w_line = nullmark;
  1013. #if WINMARK
  1014.         wp->w_mark = nullmark;
  1015. #endif
  1016.         wp->w_lastdot = nullmark;
  1017.         wp->w_toprow = 0;
  1018.         wp->w_values = global_w_values;
  1019.         wp->w_ntrows = screen
  1020.             ? term.t_nrow-2        /* "-1" for mode line.  */
  1021.             : 1;            /* command-line        */
  1022.         wp->w_force = 0;
  1023.         wp->w_flag  = WFMODE|WFHARD;            /* Full.                */
  1024.     wp->w_bufp  = NULL;
  1025.  
  1026.     if (screen) {
  1027.         (void)bsizes(bminip);    /* FIXME */
  1028.         TRACE(("winit delinking bminip, %d lines, %ld bytes\n",
  1029.             bminip->b_linecount,
  1030.             bminip->b_bytecount));
  1031.         (void) delink_bp(bminip);
  1032.     } else {
  1033.         /* create the command-buffer */
  1034.         TRACE(("winit creating bminip & wminip\n"));
  1035.         wminip = wp;
  1036.         bminip = wp->w_bufp = bfind("", BFINVS);
  1037.         b_set_scratch(bminip);
  1038.         addline(bminip, "", 0);
  1039.         wminip->w_dot = bminip->b_dot;
  1040.  
  1041.         make_local_w_val(wminip,WMDNUMBER);
  1042.         set_w_val(wminip, WMDNUMBER, FALSE);
  1043.  
  1044.         make_local_w_val(wminip,WMDLIST);
  1045.         set_w_val(wminip, WMDLIST, TRUE);
  1046. #ifdef WMDLINEWRAP
  1047.         make_local_w_val(wminip,WMDLINEWRAP);
  1048.         set_w_val(wminip, WMDLINEWRAP, FALSE);
  1049. #endif
  1050.     }
  1051. }
  1052.  
  1053. /* For memory-leak testing (only!), releases all display storage. */
  1054. #if NO_LEAKS
  1055. void    wp_leaks(void)
  1056. {
  1057.     register WINDOW *wp;
  1058.  
  1059.     while ((wp = wheadp) != 0) {
  1060.             wp = wp->w_wndp;
  1061.         free((char *)wheadp);
  1062.         wheadp = wp;
  1063.     }
  1064.     free((char *)wminip);
  1065. }
  1066. #endif
  1067.  
  1068. #if OPT_SEL_YANK || OPT_PERL
  1069. /*
  1070.  * Allocate a fake window so that we can yank a selection even if the buffer
  1071.  * containing the selection is not attached to any window.
  1072.  *
  1073.  * curwp is set to the new fake window.  A pointer to the old curwp is returned
  1074.  * for a later call to pop_fake_win() which will restore curwp.
  1075.  */
  1076.  
  1077. WINDOW *
  1078. push_fake_win(BUFFER *bp)
  1079. {
  1080.     WINDOW *oldwp = curwp;
  1081.     WINDOW *wp;
  1082.     if ((wp = typealloc(WINDOW)) == NULL) {
  1083.         (void)no_memory("WINDOW");
  1084.         return NULL;
  1085.     }
  1086.     curwp = wp;
  1087.     curwp->w_bufp = bp;
  1088.     if ((wp = bp2any_wp(bp)) == NULL)
  1089.     copy_traits(&(curwp->w_traits), &(bp->b_wtraits));
  1090.     else
  1091.     copy_traits(&(curwp->w_traits), &(wp->w_traits));
  1092.     curwp->w_flag  = 0;
  1093.     curwp->w_force = 0;
  1094.     curwp->w_toprow = wheadp->w_toprow - 2;    /* should be negative */
  1095.     curwp->w_ntrows = 1;
  1096.     curwp->w_wndp = wheadp;
  1097.     wheadp = curwp;
  1098.     return oldwp;
  1099. }
  1100.  
  1101. /*
  1102.  * kill top fake window allocated by alloc_fake_win;
  1103.  *
  1104.  * Set curwp to the oldwp parameter.
  1105.  *
  1106.  * Return 0 if no fake window popped, else return the buffer pointer
  1107.  * of the popped window.
  1108.  *
  1109.  */
  1110. BUFFER *
  1111. pop_fake_win(WINDOW *oldwp)
  1112. {
  1113.     WINDOW *wp;
  1114.     BUFFER *bp;
  1115.  
  1116.     curwp = oldwp;
  1117.  
  1118.     wp = wheadp;
  1119.     if (wp->w_toprow >= 0)
  1120.     return NULL;                /* not a fake window */
  1121.  
  1122.     bp = wp->w_bufp;
  1123.     /* unlink and free the fake window */
  1124.     wheadp = wp->w_wndp;
  1125.     free((char *)wp);
  1126.     return bp;
  1127. }
  1128.  
  1129. #endif
  1130.