home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / x / xvisrc.zoo / windows.c < prev    next >
C/C++ Source or Header  |  1992-07-28  |  10KB  |  472 lines

  1. /* Copyright (c) 1990,1991,1992 Chris and John Downey */
  2. #ifndef lint
  3. static char *sccsid = "@(#)windows.c    2.2 (Chris & John Downey) 8/28/92";
  4. #endif
  5.  
  6. /***
  7.  
  8. * program name:
  9.     xvi
  10. * function:
  11.     PD version of UNIX "vi" editor, with extensions.
  12. * module name:
  13.     windows.c
  14. * module function:
  15.     Window handling functions.
  16. * history:
  17.     STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  18.     Originally by Tim Thompson (twitch!tjt)
  19.     Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  20.     Heavily modified by Chris & John Downey
  21.  
  22. ***/
  23.  
  24. #include "xvi.h"
  25.  
  26. #undef    min
  27. #define    min(a, b)    (((a) < (b)) ? (a) : (b))
  28.  
  29. static    int    nwindows = 0;
  30.  
  31. static    Xviwin    *new_window P((Xviwin *, Xviwin *));
  32. static    bool_t    setup_window P((Xviwin *));
  33.  
  34. Xviwin *
  35. init_window(vs)
  36. VirtScr    *vs;
  37. {
  38.     Xviwin    *newwin;
  39.  
  40.     newwin = new_window((Xviwin *) NULL, (Xviwin *) NULL);
  41.     if (newwin == NULL) {
  42.     return(NULL);
  43.     }
  44.  
  45.     newwin->w_vs = vs;
  46.     newwin->w_nrows = (*vs->v_rows)(vs);
  47.     newwin->w_ncols = (*vs->v_cols)(vs);
  48.  
  49.     /*
  50.      * Initialise screen stuff.
  51.      */
  52.     init_screen(newwin);
  53.  
  54.     newwin->w_winpos = 0;
  55.     newwin->w_cmdline = Rows - 1;
  56.  
  57.     return(newwin);
  58. }
  59.  
  60. /*
  61.  * Split the given window in half, placing a new empty
  62.  * window in the bottom section and resizing the old one
  63.  * in the top half.
  64.  */
  65. Xviwin *
  66. split_window(oldwin)
  67. Xviwin    *oldwin;
  68. {
  69.     Xviwin    *newwin;
  70.  
  71.     /*
  72.      * Make sure there are enough rows for the new window.
  73.      * This does not obey the minrows parameter, because
  74.      * the point is to have enough space to actually display
  75.      * a window, not just to have a zero-size one.
  76.      */
  77.     if (oldwin->w_nrows < (MINROWS * 2))
  78.     return(NULL);
  79.  
  80.     newwin = new_window(oldwin, oldwin->w_next);
  81.     if (newwin == NULL) {
  82.     return(NULL);
  83.     }
  84.  
  85.     newwin->w_vs = oldwin->w_vs;
  86.  
  87.     /*
  88.      * Calculate size and position of new and old windows.
  89.      */
  90.     newwin->w_nrows = oldwin->w_nrows / 2;
  91.     newwin->w_cmdline = oldwin->w_cmdline;
  92.     newwin->w_winpos = (newwin->w_cmdline - newwin->w_nrows) + 1;
  93.  
  94.     oldwin->w_nrows -= newwin->w_nrows;
  95.     oldwin->w_cmdline = newwin->w_winpos - 1;
  96.  
  97.     newwin->w_ncols = oldwin->w_ncols;
  98.  
  99.     return(newwin);
  100. }
  101.  
  102. /*
  103.  * Delete the given window.
  104.  */
  105. void
  106. free_window(window)
  107. Xviwin    *window;
  108. {
  109.     if (window == NULL || nwindows < 1)
  110.     return;
  111.  
  112.     if (window->w_next != NULL) {
  113.     window->w_next->w_last = window->w_last;
  114.     }
  115.     if (window->w_last != NULL) {
  116.     window->w_last->w_next = window->w_next;
  117.     }
  118.     nwindows -= 1;
  119.  
  120.     window->w_buffer->b_nwindows -= 1;
  121.  
  122.     free((char *) window->w_cursor);
  123.     flexdelete(&window->w_statusline);
  124.     free((char *) window);
  125. }
  126.  
  127. /*
  128.  * Allocate a new window.
  129.  */
  130. static Xviwin *
  131. new_window(last, next)
  132. Xviwin    *last, *next;
  133. {
  134.     Xviwin    *newwin;
  135.  
  136.     newwin = (Xviwin *) malloc(sizeof(Xviwin));
  137.     if (newwin == NULL) {
  138.     return(NULL);
  139.     }
  140.  
  141.     if (setup_window(newwin) == FALSE) {
  142.     free((char *) newwin);
  143.     return(NULL);
  144.     }
  145.  
  146.     /*
  147.      * Link the window into the list.
  148.      */
  149.     if (last != NULL) {
  150.     last->w_next = newwin;
  151.     }
  152.     if (next != NULL) {
  153.     next->w_last = newwin;
  154.     }
  155.     newwin->w_last = last;
  156.     newwin->w_next = next;
  157.     nwindows += 1;
  158.  
  159.     return(newwin);
  160. }
  161.  
  162. /*
  163.  * Set up and allocate data structures for the given window,
  164.  * assumed to contain a valid pointer to a buffer.
  165.  *
  166.  * This routine should be called after setup_buffer().
  167.  */
  168. static bool_t
  169. setup_window(w)
  170. Xviwin    *w;
  171. {
  172.     /*
  173.      * Allocate space for the status line.
  174.      */
  175.     flexnew(&w->w_statusline);
  176.  
  177.     /*
  178.      * Allocate a Posn structure for the cursor.
  179.      */
  180.     w->w_cursor = (Posn *) malloc(sizeof(Posn));
  181.     if (w->w_cursor == NULL) {
  182.     return(FALSE);
  183.     }
  184.  
  185.     return(TRUE);
  186. }
  187.  
  188. void
  189. map_window_onto_buffer(w, b)
  190. Xviwin    *w;
  191. Buffer    *b;
  192. {
  193.     /*
  194.      * Connect the two together.
  195.      */
  196.     w->w_buffer = b;
  197.     b->b_nwindows += 1;
  198.  
  199.     /*
  200.      * Put the cursor and the screen in the right place.
  201.      */
  202.     move_cursor(w, b->b_file, 0);
  203.     w->w_topline = b->b_file;
  204.     w->w_botline = b->b_lastline;
  205.  
  206.     /*
  207.      * Miscellany.
  208.      */
  209.     w->w_row = w->w_col = 0;
  210.     w->w_virtcol = 0;
  211.     w->w_curswant = 0;
  212.     w->w_set_want_col = FALSE;
  213.     w->w_curs_new = TRUE;
  214. }
  215.  
  216. /*
  217.  * Unmap the given window from its buffer.
  218.  * We don't need to do much here, on the assumption that the
  219.  * calling code is going to do a map_window_onto_buffer()
  220.  * immediately afterwards; the vital thing is to decrement
  221.  * the window reference count.
  222.  */
  223. void
  224. unmap_window(w)
  225. Xviwin    *w;
  226. {
  227.     w->w_buffer->b_nwindows -= 1;
  228.  
  229.     w->w_cursor->p_line = NULL;
  230.     w->w_topline = NULL;
  231.     w->w_botline = NULL;
  232. }
  233.  
  234. /*
  235.  * Given a window, find the "next" one in the list.
  236.  */
  237. Xviwin *
  238. next_window(window)
  239. Xviwin    *window;
  240. {
  241.     if (window == NULL) {
  242.     return(NULL);
  243.     } else if (window->w_next != NULL) {
  244.     return(window->w_next);
  245.     } else {
  246.     Xviwin    *tmp;
  247.  
  248.     /*
  249.      * No next window; go to start of list.
  250.      */
  251.     for (tmp = window; tmp->w_last != NULL; tmp = tmp->w_last)
  252.         ;
  253.     return(tmp);
  254.     }
  255. }
  256.  
  257. /*
  258.  * Find the next window onto the buffer with the given filename,
  259.  * starting at the current one; if there isn't one, or if it is
  260.  * too small to move into, return NULL.
  261.  */
  262. Xviwin *
  263. find_window(window, filename)
  264. Xviwin    *window;
  265. char    *filename;
  266. {
  267.     Xviwin    *wp;
  268.     char    *f;
  269.  
  270.     if (window != NULL && filename != NULL) {
  271.     wp = window;
  272.     do {
  273.         f = wp->w_buffer->b_filename;
  274.         if (f != NULL && strcmp(filename, f) == 0) {
  275.         return(wp);
  276.         }
  277.         wp = next_window(wp);
  278.     } while (wp != window);
  279.     }
  280.  
  281.     return(NULL);
  282. }
  283.  
  284. /*
  285.  * Grow or shrink the given buffer window by "nlines" lines.
  286.  * We prefer to move the bottom of the window, and will only
  287.  * move the top when there is no room for manoeuvre below
  288.  * the current one - i.e. any windows are at minimum size.
  289.  */
  290. void
  291. resize_window(window, nlines)
  292. Xviwin    *window;
  293. int    nlines;
  294. {
  295.     unsigned    savecho;
  296.  
  297.     if (nlines == 0 || nwindows == 1) {
  298.     /*
  299.      * Nothing to do.
  300.      */
  301.     return;
  302.     }
  303.  
  304.     savecho = echo;
  305.  
  306.     if (nlines < 0) {
  307.     int    spare;        /* num spare lines in this window */
  308.  
  309.     nlines = - nlines;
  310.  
  311.     /*
  312.      * The current window must always contain 2 rows,
  313.      * so that the cursor has somewhere to go.
  314.      */
  315.     spare = window->w_nrows - MINROWS;
  316.  
  317.     /*
  318.      * If the window is already as small as it
  319.      * can get, don't bother to do anything.
  320.      */
  321.     if (spare <= 0)
  322.         return;
  323.  
  324.     /*
  325.      * Don't allow any screen updating until we've
  326.      * finished moving things around.
  327.      */
  328.     echo &= ~e_CHARUPDATE;
  329.  
  330.     /*
  331.      * First shrink the current window up from the bottom.
  332.      *
  333.      * move_sline()'s return value should be negative or 0
  334.      * in this case.
  335.      */
  336.     nlines += move_sline(window, - min(spare, nlines));
  337.  
  338.     /*
  339.      * If that wasn't enough, grow the window above us
  340.      * by the appropriate number of lines.
  341.      */
  342.     if (nlines > 0) {
  343.         (void) move_sline(window->w_last, nlines);
  344.     }
  345.     } else {
  346.     /*
  347.      * Don't allow any screen updating until we've
  348.      * finished moving things around.
  349.      */
  350.     echo &= ~e_CHARUPDATE;
  351.  
  352.     /*
  353.      * Expand window.
  354.      */
  355.     nlines -= move_sline(window, nlines);
  356.     if (nlines > 0) {
  357.         (void) move_sline(window->w_last, -nlines);
  358.     }
  359.     }
  360.  
  361.     /*
  362.      * Update screen. Note that status lines have
  363.      * already been updated by move_sline().
  364.      *
  365.      * This still needs a lot more optimization.
  366.      */
  367.     echo = savecho;
  368.     update_all();
  369. }
  370.  
  371. /*
  372.  * Adjust the boundary between two adjacent windows by moving the status line
  373.  * up or down, updating parameters for both windows as appropriate.
  374.  *
  375.  * Note that this can shrink the window to size 0.
  376.  */
  377. int
  378. move_sline(wp, nlines)
  379. Xviwin    *wp;        /* window whose status line we have to move */
  380. int    nlines;        /*
  381.              * number of lines to move (negative for
  382.              * upward moves, positive for downwards)
  383.              */
  384. {
  385.     Xviwin    *nextwin;
  386.  
  387.     if (wp == NULL || (nextwin = wp->w_next) == NULL) {
  388.     return(0);
  389.     }
  390.  
  391.     if (nlines < 0) {        /* move upwards */
  392.     int    amount;
  393.     int    spare;
  394.  
  395.     amount = -nlines;
  396.     spare = wp->w_nrows - Pn(P_minrows);
  397.  
  398.     if (amount > spare && wp->w_last != NULL) {
  399.         /*
  400.          * Not enough space: call move_sline() recursively
  401.          * for previous line; note that the second parameter
  402.          * should be negative.
  403.          */
  404.         (void) move_sline(wp->w_last, spare - amount);
  405.         spare = wp->w_nrows - Pn(P_minrows);
  406.     }
  407.     if (amount > spare)
  408.         amount = spare;
  409.     if (amount != 0) {
  410.         wp->w_nrows -= amount;
  411.         wp->w_cmdline -= amount;
  412.         nextwin->w_winpos -= amount;
  413.         nextwin->w_nrows += amount;
  414.         (void) shiftdown(nextwin, (unsigned) amount);
  415.         if (wp->w_nrows > 0) {
  416.         show_file_info(wp);
  417.         }
  418.     }
  419.     nlines = -amount;    /* return value */
  420.     } else {            /* move downwards */
  421.     int    spare;
  422.  
  423.     spare = nextwin->w_nrows - Pn(P_minrows);
  424.  
  425.     if (nlines > spare) {
  426.         /*
  427.          * Not enough space: call move_sline()
  428.          * recursively for next line.
  429.          */
  430.         (void) move_sline(nextwin, nlines - spare);
  431.         spare = nextwin->w_nrows - Pn(P_minrows);
  432.     }
  433.     if (nlines > spare)
  434.         nlines = spare;
  435.     if (nlines != 0) {
  436.         wp->w_nrows += nlines;
  437.         wp->w_cmdline += nlines;
  438.         nextwin->w_winpos += nlines;
  439.         nextwin->w_nrows -= nlines;
  440.         (void) shiftup(nextwin, (unsigned) nlines);
  441.         if (wp->w_nrows > 0) {
  442.         show_file_info(wp);
  443.         }
  444.     }
  445.     }
  446.     return(nlines);
  447. }
  448.  
  449. /*
  450.  * Update all windows associated with the given buffer.
  451.  */
  452. void
  453. update_buffer(buffer)
  454. Buffer    *buffer;
  455. {
  456.     Xviwin    *w;
  457.         
  458.     w = curwin;        /* as good a place as any to start */
  459.     do {
  460.     if (w->w_buffer == buffer) {
  461.         update_window(w);
  462.     }
  463.     w = next_window(w);
  464.     } while (w != curwin);
  465. }
  466.  
  467. bool_t
  468. can_split()
  469. {
  470.     return(nwindows < Pn(P_autosplit));
  471. }
  472.