home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR8 / TDE32.ZIP / WINDOW.C < prev    next >
C/C++ Source or Header  |  1993-11-13  |  41KB  |  1,308 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - window module
  10.  * Purpose: This file contains the code associated with opening and sizing
  11.  *           windows, and also displaying the help window.
  12.  * File:    window.c
  13.  * Author:  Douglas Thomson
  14.  * System:  this file is intended to be system-independent
  15.  * Date:    October 12, 1989
  16.  */
  17. /*********************  end of original comments   ********************/
  18.  
  19.  
  20. /*
  21.  * The window routines have been EXTENSIVELY rewritten.  Some routines were
  22.  * changed so only one logical function is carried out, eg. 'initialize_window'.
  23.  * I like the Microsoft way of resizing windows - just press the up and down
  24.  * arrows to adjust the window to desired size.  I also like pressing one key
  25.  * to change windows.  All of which are implemented in TDE.
  26.  *
  27.  * In TDE, version 1.4, I added support for vertical windows.
  28.  *
  29.  * New editor name:  TDE, the Thomson-Davis Editor.
  30.  * Author:           Frank Davis
  31.  * Date:             June 5, 1991, version 1.0
  32.  * Date:             July 29, 1991, version 1.1
  33.  * Date:             October 5, 1991, version 1.2
  34.  * Date:             January 20, 1992, version 1.3
  35.  * Date:             February 17, 1992, version 1.4
  36.  * Date:             April 1, 1992, version 1.5
  37.  * Date:             June 5, 1992, version 2.0
  38.  * Date:             October 31, 1992, version 2.1
  39.  * Date:             April 1, 1993, version 2.2
  40.  * Date:             June 5, 1993, version 3.0
  41.  * Date:             August 29, 1993, version 3.1
  42.  * Date:             November 13, 1993, version 3.2
  43.  *
  44.  * This modification of Douglas Thomson's code is released into the
  45.  * public domain, Frank Davis.  You may distribute it freely.
  46.  */
  47.  
  48. #include "tdestr.h"
  49. #include "common.h"
  50. #include "define.h"
  51. #include "tdefunc.h"
  52.  
  53.  
  54. /*
  55.  * Name:    initialize_window
  56.  * Purpose: To open a new window
  57.  * Date:    June 5, 1991
  58.  * Modified: November 13, 1993, Frank Davis per Byrial Jensen
  59.  * Returns: OK if window opened successfully
  60.  *          ERROR if anything went wrong
  61.  * Notes:   If this is first window, then set up as normal displayed window;
  62.  *          otherwise, make the present window invisible and open a new
  63.  *          window in the same screen location as the old one.
  64.  *
  65.  * Change:  Use of new function get_next_letter( )
  66.  */
  67. int  initialize_window( void )
  68. {
  69. int  top;
  70. int  bottom;
  71. int  start_col;
  72. int  end_col;
  73. TDE_WIN *wp;        /* used for scanning windows */
  74. TDE_WIN *window;
  75. register file_infos *fp;     /* used for scanning files */
  76. register int rc;
  77. line_list_ptr ll;
  78. line_list_ptr temp_ll;
  79.  
  80.    rc = OK;
  81.    window = g_status.current_window;
  82.    fp = g_status.current_file;
  83.    if (window == NULL) {
  84.       /*
  85.        * special case if this is the first window on screen.
  86.        */
  87.       top = start_col = 0;
  88.       bottom  = g_display.nlines;
  89.       end_col = g_display.ncols - 1;
  90.    } else {
  91.       /*
  92.        * else put the new window in same place as current window.
  93.        *  make current window invisible.  new window becomes current window.
  94.        */
  95.       top       = window->top_line - 1;
  96.       bottom    = window->bottom_line;
  97.       start_col = window->start_col;
  98.       end_col   = window->end_col;
  99.    }
  100.  
  101.    assert( top < bottom );
  102.    assert( start_col < end_col );
  103.    assert( fp != NULL );
  104.  
  105.    if (create_window( &wp, top, bottom, start_col, end_col, fp ) == ERROR) {
  106.       /*
  107.        * out of memory
  108.        */
  109.       error( WARNING, bottom, main4 );
  110.  
  111.       /*
  112.        * This is a real nuisance. We had room for the file and the
  113.        *  file structure, but not enough for the window as well.
  114.        * Now we must free all the memory that has already been
  115.        *  allocated.
  116.        */
  117.       if (fp->ref_count == 0) {
  118.  
  119.          /*
  120.           * remove fp from file pointer list.
  121.           */
  122.          if (fp->prev != NULL)
  123.             fp->prev->next = fp->next;
  124.          else
  125.             g_status.file_list = fp->next;
  126.  
  127.          if (fp->next != NULL)
  128.             fp->next->prev = fp->prev;
  129.  
  130.          /*
  131.           * free the undo stack, line pointers, and linked list.
  132.           */
  133.  
  134.          ll = fp->undo_top;
  135.          while (ll != NULL) {
  136.             temp_ll = ll->next;
  137.             if (ll->line != NULL)
  138.                my_free( ll->line );
  139.             my_free( ll );
  140.             ll = temp_ll;
  141.          }
  142.  
  143.          ll = fp->line_list;
  144.          while (ll != NULL) {
  145.             temp_ll = ll->next;
  146.             if (ll->line != NULL)
  147.                my_free( ll->line );
  148.             my_free( ll );
  149.             ll = temp_ll;
  150.          }
  151.  
  152. #if defined( __MSC__ )
  153.          _fheapmin( );
  154. #endif
  155.  
  156.          free( fp );
  157.          wp = g_status.current_window;
  158.          if (wp != NULL && wp->visible)
  159.             g_status.current_file = wp->file_info;
  160.          else
  161.             g_status.stop = TRUE;
  162.       }
  163.       rc = ERROR;
  164.    }
  165.  
  166.    if (rc != ERROR) {
  167.       /*
  168.        * set up the new cursor position as appropriate
  169.        */
  170.       wp->ccol = wp->start_col;
  171.       wp->rcol = wp->bcol = 0;
  172.       wp->rline = 1L;
  173.       wp->ll    = fp->line_list;
  174.       wp->visible = TRUE;
  175.       wp->letter = get_next_letter( fp->next_letter++ );
  176.       if (window != NULL)
  177.          window->visible = FALSE;
  178.  
  179.       /*
  180.        * the new window becomes the current window.
  181.        */
  182.       g_status.current_window = wp;
  183.    }
  184.    return( rc );
  185. }
  186.  
  187.  
  188. /*
  189.  * Name:    get_next_letter
  190.  * Purpose: To find next letter to use as a window name
  191.  * Date:    August 29, 1993
  192.  * Author:  Byrial Jensen
  193.  * Passed:  next_letter:  The number window to create starting from 0
  194.  *          (Yes, the name is not very good, but I want to keep the
  195.  *          changes as small as possible)
  196.  */
  197. int  get_next_letter( int next_letter )
  198. {
  199.    if (next_letter + 1 > (int)strlen( windowletters ) )
  200.       return( LAST_WINDOWLETTER );
  201.    else
  202.       return( (int) (windowletters[next_letter]) );
  203. }
  204.  
  205.  
  206. /*
  207.  * Name:    next_window
  208.  * Purpose: To move to the next visible window.
  209.  * Date:    June 5, 1991
  210.  * Passed:  window:  pointer to current window
  211.  * Notes:   Start with current window.  If next window exists then go to it
  212.  *           else go to the first (top) window on screen.
  213.  *          When I added vertical windows, finding the "correct" next
  214.  *           window became extremely, unnecessarily, unmanageably complicated.
  215.  *           let's just use a simple procedure to find the first available,
  216.  *           visible, next window.
  217.  */
  218. int  next_window( TDE_WIN *window )
  219. {
  220. register TDE_WIN *wp;
  221. int  change;
  222.  
  223.    if (window != NULL) {
  224.       change = FALSE;
  225.       /*
  226.        * start with current window and look for first next
  227.        *  visible window
  228.        */
  229.       wp = window->next;
  230.       while (wp != NULL) {
  231.          if (wp->visible) {
  232.             change = TRUE;
  233.             break;
  234.          }
  235.          wp = wp->next;
  236.       }
  237.  
  238.       /*
  239.        * if we haven't found a visible window yet, go to the beginning of
  240.        *  the list until we find a visible window.
  241.        */
  242.       if (!change) {
  243.          wp = g_status.window_list;
  244.          while (wp != window) {
  245.             if (wp->visible) {
  246.                change = TRUE;
  247.                break;
  248.             }
  249.             wp = wp->next;
  250.          }
  251.       }
  252.       if (change == TRUE) {
  253.          entab_linebuff( );
  254.          un_copy_line( window->ll, window, TRUE );
  255.          g_status.current_window = wp;
  256.          g_status.current_file = wp->file_info;
  257.       }
  258.    }
  259.    return( OK );
  260. }
  261.  
  262.  
  263. /*
  264.  * Name:    prev_window
  265.  * Purpose: To move to the previous visible window.
  266.  * Date:    June 5, 1991
  267.  * Passed:  window:  pointer to current window
  268.  * Notes:   Start with current window.  If previous window exists then go to
  269.  *           it else go to the last (bottom) window on screen.  Opposite of
  270.  *           next_window.
  271.  *          when I added vertical windows, finding the "correct" previous
  272.  *           window became extremely, unnecessarily, unmanageably complicated.
  273.  *           let's just use a simple procedure to find the first available,
  274.  *           visible, previous window.
  275.  */
  276. int  prev_window( TDE_WIN *window )
  277. {
  278. register TDE_WIN *wp;
  279. int  change;
  280.  
  281.    if (window != NULL) {
  282.       change = FALSE;
  283.  
  284.       /*
  285.        * start with current window and look for first previous
  286.        *  visible window
  287.        */
  288.       wp = window->prev;
  289.       while (wp != NULL) {
  290.          if (wp->visible) {
  291.             change = TRUE;
  292.             break;
  293.          }
  294.          wp = wp->prev;
  295.       }
  296.  
  297.       /*
  298.        * if we haven't found a visible window yet, go to the end of
  299.        *  the list and work backwards until we find a visible window.
  300.        */
  301.       if (!change) {
  302.          wp = window->next;
  303.          if (wp != NULL) {
  304.             while (wp->next != NULL)
  305.                wp = wp->next;
  306.             while (wp != window) {
  307.                if (wp->visible) {
  308.                   change = TRUE;
  309.                   break;
  310.                }
  311.                wp = wp->prev;
  312.             }
  313.          }
  314.       }
  315.       if (change == TRUE) {
  316.          entab_linebuff( );
  317.          un_copy_line( window->ll, window, TRUE );
  318.          g_status.current_window = wp;
  319.          g_status.current_file = wp->file_info;
  320.       }
  321.    }
  322.    return( OK );
  323. }
  324.  
  325.  
  326. /*
  327.  * Name:    split_horizontal
  328.  * Purpose: To split screen horizontally at the cursor.
  329.  * Date:    June 5, 1991
  330.  * Modified: November 13, 1993, Frank Davis per Byrial Jensen
  331.  * Passed:  window:  pointer to current window
  332.  * Notes:   split the screen horizontally at the cursor position.
  333.  */
  334. int  split_horizontal( TDE_WIN *window )
  335. {
  336. register TDE_WIN *wp;
  337. register TDE_WIN *win;  /* register pointer for window */
  338. TDE_WIN *temp;
  339. file_infos *file;       /* file structure for file belonging to new window */
  340. int  rc;
  341.  
  342.    rc = OK;
  343.    win = window;
  344.    if ( win != NULL) {
  345.  
  346.       /*
  347.        * check that there is room for the window
  348.        */
  349.       if (win->bottom_line - win->cline < 2) {
  350.          /*
  351.           * move cursor up first
  352.           */
  353.          error( WARNING, win->bottom_line, win1 );
  354.          rc = ERROR;
  355.       } else {
  356.          file = win->file_info;
  357.  
  358.          assert( file != NULL );
  359.  
  360.          if (create_window( &temp, win->cline+1, win->bottom_line,
  361.                             win->start_col, win->end_col, file ) == ERROR) {
  362.             /*
  363.              * out of memory
  364.              */
  365.             error( WARNING, win->bottom_line, main4 );
  366.             rc = ERROR;
  367.          }
  368.          if (rc == OK  &&  temp != NULL) {
  369.             entab_linebuff( );
  370.             un_copy_line( win->ll, win, TRUE );
  371.             wp = temp;
  372.             /*
  373.              * record that the current window has lost some lines from
  374.              *  the bottom for the new window, and adjust its page size
  375.              *  etc accordingly.
  376.              */
  377.             win->bottom_line = win->cline;
  378.             setup_window( win );
  379.             display_current_window( win );
  380.  
  381.             /*
  382.              * set up the new cursor position as appropriate
  383.              */
  384.             wp->rcol = win->rcol;
  385.             wp->ccol = win->ccol;
  386.             wp->bcol = win->bcol;
  387.             wp->rline = win->rline;
  388.             wp->bin_offset = win->bin_offset;
  389.             wp->ll    = win->ll;
  390.             wp->cline = wp->cline + win->cline - (win->top_line + win->ruler);
  391.             if (wp->cline > wp->bottom_line)
  392.                wp->cline = wp->bottom_line;
  393.             wp->visible = TRUE;
  394.             wp->vertical = win->vertical;
  395.             wp->letter = get_next_letter( file->next_letter++ );
  396.             wp->ruler  = mode.ruler;
  397.  
  398.             /*
  399.              * the new window becomes the current window.
  400.              */
  401.             g_status.current_window = wp;
  402.  
  403.             show_window_count( g_status.window_count );
  404.             show_window_header( wp );
  405.             display_current_window( wp );
  406.             if (wp->vertical)
  407.                show_vertical_separator( wp );
  408.             make_ruler( wp );
  409.             show_ruler( wp );
  410.             rc = OK;
  411.          }
  412.       }
  413.    } else
  414.       rc = ERROR;
  415.    return( rc );
  416. }
  417.  
  418.  
  419. /*
  420.  * Name:    split_vertical
  421.  * Purpose: To split screen vertically at the cursor.
  422.  * Date:    June 5, 1991
  423.  * Modified: November 13, 1993, Frank Davis per Byrial Jensen
  424.  * Passed:  window:  pointer to current window
  425.  * Notes:   split the screen vertically at the cursor position.
  426.  *
  427.  * Change:  Use of new function: get_next_letter( )
  428.  */
  429. int  split_vertical( TDE_WIN *window )
  430. {
  431. register TDE_WIN *wp;
  432. register TDE_WIN *win;  /* register pointer for window */
  433. TDE_WIN *temp;
  434. file_infos *file;       /* file structure for file belonging to new window */
  435. int  rc;
  436.  
  437.    rc = OK;
  438.    win = window;
  439.    if (win != NULL) {
  440.  
  441.       /*
  442.        * check that there is room for the window
  443.        */
  444.       if (win->start_col + 15 > win->ccol) {
  445.          /*
  446.           * move cursor right first
  447.           */
  448.          error( WARNING, win->bottom_line, win2 );
  449.          rc = ERROR;
  450.       } else if (win->end_col - 15 < win->ccol) {
  451.          /*
  452.           * move cursor left first
  453.           */
  454.          error( WARNING, win->bottom_line, win3 );
  455.          rc = ERROR;
  456.       } else {
  457.          file = win->file_info;
  458.  
  459.          assert( file != NULL );
  460.  
  461.          if (create_window( &temp, win->top_line-1, win->bottom_line,
  462.                             win->ccol+1, win->end_col, file ) == ERROR) {
  463.             /*
  464.              * out of memory
  465.              */
  466.             error( WARNING, win->bottom_line, main4 );
  467.             rc = ERROR;
  468.          }
  469.  
  470.          if (rc == OK  &&  temp != NULL) {
  471.             entab_linebuff( );
  472.             un_copy_line( win->ll, win, TRUE );
  473.             wp = temp;
  474.  
  475.             /*
  476.              * record that the current window has lost some columns from
  477.              *  the window to the left for the new window
  478.              */
  479.             win->ccol = win->end_col = win->ccol - 1;
  480.             win->rcol--;
  481.             win->vertical = TRUE;
  482.             show_window_header( win );
  483.             show_vertical_separator( win );
  484.             display_current_window( win );
  485.             make_ruler( win );
  486.             show_ruler( win );
  487.             show_ruler_pointer( win );
  488.  
  489.             /*
  490.              * set up the new cursor position as appropriate
  491.              */
  492.             wp->rcol = win->rcol;
  493.             wp->ccol = wp->start_col + win->ccol - win->start_col;
  494.             if (wp->ccol > wp->end_col)
  495.                wp->ccol = wp->end_col;
  496.             wp->bcol  = win->bcol;
  497.             wp->rline = win->rline;
  498.             wp->bin_offset = win->bin_offset;
  499.             wp->ll       = win->ll;
  500.             wp->cline    = win->cline;
  501.             wp->visible  = TRUE;
  502.             wp->vertical = TRUE;
  503.             wp->letter   = get_next_letter( file->next_letter++ );
  504.             wp->ruler    = mode.ruler;
  505.  
  506.             /*
  507.              * the new window becomes the current window.
  508.              */
  509.             g_status.current_window = wp;
  510.  
  511.             check_virtual_col( wp, wp->rcol, wp->ccol );
  512.             wp->file_info->dirty = FALSE;
  513.             show_window_count( g_status.window_count );
  514.             show_window_header( wp );
  515.             display_current_window( wp );
  516.             make_ruler( wp );
  517.             show_ruler( wp );
  518.          }
  519.       }
  520.    } else
  521.       rc = ERROR;
  522.    return( rc );
  523. }
  524.  
  525.  
  526. /*
  527.  * Name:    show_vertical_separator
  528.  * Purpose: To separate vertical screens
  529.  * Date:    June 5, 1991
  530.  * Passed:  window:  pointer to current window
  531.  */
  532. void show_vertical_separator( TDE_WIN *window )
  533. {
  534. int  i;
  535. int  line;
  536. int  col;
  537.  
  538.    line = window->top_line - 1;
  539.    col  = window->end_col + 1;
  540.    if (col < g_display.ncols - 1) {
  541.       i = window->bottom_line - line;
  542.  
  543.       assert( i <= g_display.nlines );
  544.  
  545.       while (i-- >= 0)
  546.          c_output( VERTICAL_CHAR, col, line++, g_display.head_color );
  547.    }
  548. }
  549.  
  550.  
  551. /*
  552.  * Name:    size_window
  553.  * Purpose: To change the size of the current and one other window.
  554.  * Date:    June 5, 1991
  555.  * Passed:  window:  pointer to current window
  556.  * Notes:   Use the Up and Down arrow keys to make the current window
  557.  *           bigger or smaller.  The window above will either grow
  558.  *           or contract accordingly.
  559.  */
  560. int  size_window( TDE_WIN *window )
  561. {
  562. int  func;
  563. int  c;
  564. int  resize;
  565. int  show_above_ruler;
  566. int  old_bottom_line;
  567. int  old_top_line;
  568. int  new_bottom_line;
  569. int  new_top_line;
  570. register TDE_WIN *above;
  571. register TDE_WIN *win;
  572. #if defined( __UNIX__ )
  573.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  574. #else
  575.  char display_buff[(MAX_COLS+2)*2];
  576. #endif
  577.  
  578.    win = window;
  579.    if (win->top_line != 1 && !win->vertical) {
  580.       entab_linebuff( );
  581.       un_copy_line( win->ll, win, TRUE );
  582.       save_screen_line( 0, win->bottom_line, display_buff );
  583.  
  584.       /*
  585.        * press up or down to change window size
  586.        */
  587.       set_prompt( win4, win->bottom_line );
  588.  
  589.       /*
  590.        * resizing only affects current window and above visible window
  591.        */
  592.       above = g_status.window_list;
  593.       while (above->bottom_line + 2 != win->top_line || !above->visible)
  594.          above = above->next;
  595.       if (above->vertical)
  596.          /*
  597.           * cannot resize vertical window
  598.           */
  599.          error( WARNING, win->bottom_line, win5 );
  600.       else {
  601.          old_top_line = win->top_line;
  602.          old_bottom_line = above->bottom_line;
  603.          show_above_ruler = FALSE;
  604.          for (func=0; func != AbortCommand && func != Rturn; ) {
  605.  
  606.             /*
  607.              * If user has redined the ESC and Return keys, make them Rturn and
  608.              *  AbortCommand in this function.
  609.              */
  610.             c = getkey( );
  611.             func = getfunc( c );
  612.             if (c == RTURN || func == NextLine || func == BegNextLine)
  613.                func = Rturn;
  614.             else if (c == ESC)
  615.                func = AbortCommand;
  616.             resize = FALSE;
  617.  
  618.             /*
  619.              * if LineUp, make current window top line grow and bottom line
  620.              *  of above window shrink.  if window movement covers up current
  621.              *  line of window then we must adjust logical line and real line.
  622.              */
  623.             if (func == LineUp) {
  624.                if (above->bottom_line > above->top_line + above->ruler) {
  625.                   if (win->rline == (win->cline - (win->top_line+win->ruler-1)))
  626.                      --win->cline;
  627.                   --win->top_line;
  628.                   if (above->cline == above->bottom_line)
  629.                      --above->cline;
  630.                   --above->bottom_line;
  631.                   resize = TRUE;
  632.                   if (mode.ruler) {
  633.                      if (win->ruler == FALSE) {
  634.                         if (win->cline == win->top_line)
  635.                            ++win->cline;
  636.                         if (win->cline > win->bottom_line)
  637.                            win->cline = win->bottom_line;
  638.                         win->ruler = TRUE;
  639.                      }
  640.                   }
  641.                }
  642.  
  643.             /*
  644.              * if LineDown, make current window top line shrink and bottom line
  645.              *  of above window grow.  if window movement covers up current
  646.              *  line of window then we must adjust logical line and real line.
  647.              */
  648.             } else if (func == LineDown) {
  649.                if (win->bottom_line > win->top_line + win->ruler) {
  650.                   if (win->cline == win->top_line + win->ruler)
  651.                      ++win->cline;
  652.                   ++win->top_line;
  653.                   ++above->bottom_line;
  654.                   resize = TRUE;
  655.                   if (mode.ruler) {
  656.                      if (above->ruler == FALSE) {
  657.                         if (above->cline == above->top_line)
  658.                            ++above->cline;
  659.                         if (above->cline > above->bottom_line)
  660.                            above->cline = above->bottom_line;
  661.                         above->ruler = TRUE;
  662.                         make_ruler( above );
  663.                         show_above_ruler = TRUE;
  664.                      }
  665.                   }
  666.                }
  667.             }
  668.  
  669.             /*
  670.              * if we resize a window, then update window size and current and
  671.              *  real lines if needed.
  672.              */
  673.             if (resize == TRUE) {
  674.                setup_window( above );
  675.                display_current_window( above );
  676.                if (show_above_ruler) {
  677.                   show_ruler( above );
  678.                   show_ruler_pointer( above );
  679.                   show_above_ruler = FALSE;
  680.                }
  681.                setup_window( win );
  682.                show_window_header( win );
  683.                win->ruler = mode.ruler;
  684.                make_ruler( win );
  685.                show_ruler( win );
  686.                show_ruler_pointer( win );
  687.                display_current_window( win );
  688.                save_screen_line( 0, win->bottom_line, display_buff );
  689.  
  690.                /*
  691.                 * press up or down to change window size
  692.                 */
  693.                set_prompt( win4, win->bottom_line );
  694.             }
  695.          }
  696.          new_top_line = win->top_line;
  697.          new_bottom_line = above->bottom_line;
  698.          for (above=g_status.window_list; above != NULL; above=above->next) {
  699.             if (!above->visible) {
  700.                if (above->bottom_line == old_bottom_line) {
  701.                   above->bottom_line = new_bottom_line;
  702.                   if (above->cline < new_bottom_line)
  703.                      above->cline = new_bottom_line;
  704.                   setup_window( above );
  705.                } else if (above->top_line == old_top_line) {
  706.                   above->top_line = new_top_line;
  707.                   if (above->cline < new_top_line)
  708.                      above->cline = new_top_line;
  709.                   if ((long)(above->cline+1L - (above->top_line+above->ruler)) >
  710.                                                                 above->rline)
  711.                      above->cline = (int)above->rline + above->top_line +
  712.                                      above->ruler - 1;
  713.                   setup_window( above );
  714.                }
  715.             }
  716.          }
  717.       }
  718.       restore_screen_line( 0, win->bottom_line, display_buff );
  719.    } else {
  720.      if (win->vertical)
  721.         /*
  722.          * cannot resize vertical window
  723.          */
  724.         error( WARNING, win->bottom_line, win5 );
  725.      else
  726.         /*
  727.          * cannot resize top window
  728.          */
  729.         error( WARNING, win->bottom_line, win6 );
  730.    }
  731.    return( OK );
  732. }
  733.  
  734.  
  735. /*
  736.  * Name:    zoom_window
  737.  * Purpose: To blow-up current window.
  738.  * Date:    September 1, 1991
  739.  * Passed:  window:  pointer to current window
  740.  * Notes:   Make all windows, visible and hidden, full size.
  741.  */
  742. int  zoom_window( TDE_WIN *window )
  743. {
  744. register TDE_WIN *wp;
  745.  
  746.    if (window != NULL) {
  747.       entab_linebuff( );
  748.       un_copy_line( window->ll, window, TRUE );
  749.       for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  750.          if (wp != window && wp->visible)
  751.             wp->visible = FALSE;
  752.  
  753.          /*
  754.           * can't diff one window, reset the diff
  755.           */
  756.          diff.defined = FALSE;
  757.          if (wp->top_line != 1)
  758.             wp->cline = wp->cline - (wp->top_line+wp->ruler) + 1;
  759.          wp->top_line = 1;
  760.          wp->bottom_line = g_display.nlines;
  761.          wp->end_col   = g_display.ncols - 1;
  762.          wp->start_col = 0;
  763.          wp->vertical  = FALSE;
  764.          check_virtual_col( wp, wp->rcol, wp->ccol );
  765.          make_ruler( wp );
  766.       }
  767.       redraw_screen( window );
  768.       show_ruler( window );
  769.    }
  770.    return( OK );
  771. }
  772.  
  773.  
  774. /*
  775.  * Name:    next_hidden_window
  776.  * Purpose: To display the window that is "behind" current window.
  777.  * Date:    September 1, 1991
  778.  * Passed:  window:  pointer to current window
  779.  */
  780. int  next_hidden_window( TDE_WIN *window )
  781. {
  782. int  poof = FALSE;
  783. register TDE_WIN *wp;
  784.  
  785.    if (window != NULL) {
  786.  
  787.       /*
  788.        * look for next hidden window starting with current window.
  789.        */
  790.       wp = window;
  791.       for (wp=window->next; wp != NULL && !poof; ) {
  792.          if (!wp->visible)
  793.             poof = TRUE;
  794.          else
  795.             wp = wp->next;
  796.       }
  797.  
  798.       /*
  799.        * if we haven't found an invisible window yet, start looking
  800.        *  for a hidden window from the beginning of the window list.
  801.        */
  802.       if (!poof) {
  803.          for (wp=g_status.window_list; wp != NULL && !poof; ) {
  804.             if (!wp->visible)
  805.                poof = TRUE;
  806.             else
  807.                wp = wp->next;
  808.          }
  809.       }
  810.  
  811.       if (poof) {
  812.          entab_linebuff( );
  813.          un_copy_line( window->ll, window, TRUE );
  814.          wp->cline = window->top_line + window->ruler +
  815.                        (wp->cline - (wp->top_line + wp->ruler));
  816.          wp->top_line = window->top_line;
  817.          wp->bottom_line = window->bottom_line;
  818.          wp->start_col = window->start_col;
  819.          wp->end_col   = window->end_col;
  820.          wp->vertical  = window->vertical;
  821.          if (wp->cline < wp->top_line + wp->ruler)
  822.             wp->cline = wp->top_line + wp->ruler;
  823.          if (wp->cline > wp->bottom_line)
  824.             wp->cline = wp->bottom_line;
  825.          if ((wp->cline+1L - (wp->top_line+wp->ruler)) > wp->rline)
  826.             wp->cline = (int)wp->rline + wp->top_line + wp->ruler - 1;
  827.          check_virtual_col( wp, wp->rcol, wp->ccol );
  828.          wp->visible = TRUE;
  829.          window->visible = FALSE;
  830.          if (diff.defined  &&  (diff.w1 == window  ||  diff.w2 == window))
  831.             diff.defined = FALSE;
  832.          g_status.current_window = wp;
  833.          redraw_current_window( wp );
  834.          make_ruler( wp );
  835.          show_ruler( wp );
  836.       }
  837.    }
  838.    return( OK );
  839. }
  840.  
  841.  
  842. /*
  843.  * Name:    setup_window
  844.  * Purpose: To set the page length and the center line of a window, based
  845.  *           on the top and bottom lines.
  846.  * Date:    June 5, 1991
  847.  * Passed:  window: window to be set up
  848.  */
  849. void setup_window( TDE_WIN *window )
  850. {
  851.    window->page = window->bottom_line - (window->top_line + window->ruler) -
  852.                   g_status.overlap + 1;
  853.    if (window->page < 1)
  854.       window->page = 1;
  855. }
  856.  
  857.  
  858. /*
  859.  * Name:    finish
  860.  * Purpose: To remove the current window and terminate the program if no
  861.  *           more windows are left.
  862.  * Date:    June 5, 1991
  863.  * Passed:  window:  pointer to current window
  864.  * Notes:   Order of deciding which window becomes current window:
  865.  *          1) If any invisible window with same top and bottom line,
  866.  *          and start_col and end_col, then first invisible one becomes
  867.  *          current window.
  868.  *          2) window above if it exists becomes current window
  869.  *          3) window below if it exists becomes current window
  870.  *          4) window right if it exists becomes current window
  871.  *          5) window left  if it exists becomes current window
  872.  *          6) first available invisible window becomes current window.
  873.  *          When I added vertical windows, this routine became a LOT
  874.  *           more complicated.  To keep things reasonably sane, let's
  875.  *           only close windows that have three common edges, eg.
  876.  *
  877.  *                    ┌──────┬──────────┐
  878.  *                    │      │    no    │
  879.  *                    │      ├─────┬────┤
  880.  *                    │      │yes1 │yes1│
  881.  *                    │  no  ├─────┴────┤
  882.  *                    │      │   yes2   │
  883.  *                    │      ├──────────┤
  884.  *                    │      │   yes2   │
  885.  *                    └──────┴──────────┘
  886.  *
  887.  *          Windows with 'no' cannot be closed.  Windows with 'yes' can
  888.  *          be combined with windows that have the same yes number.
  889.  */
  890. void finish( TDE_WIN *window )
  891. {
  892. register TDE_WIN *wp;   /* for scanning other windows */
  893. register TDE_WIN *win;  /* register pointer for window */
  894. file_infos *file, *fp;  /* for scanning other files */
  895. int  poof;
  896. int  cline;
  897. int  top;
  898. int  bottom;
  899. int  start_col;
  900. int  end_col;
  901. int  max_letter;
  902. int  letter_index;
  903. int  file_change = FALSE;
  904. line_list_ptr ll;
  905. line_list_ptr temp_ll;
  906. int major_choice;
  907. int minor_choice;
  908. #if defined( __UNIX__ )
  909.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  910. #else
  911.  char display_buff[(MAX_COLS+2)*2];
  912. #endif
  913.  
  914.    win = window;
  915.    entab_linebuff( );
  916.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  917.       return;
  918.  
  919.    file = win->file_info;
  920.    /*
  921.     * remove all hidden windows that point to same file
  922.     */
  923.    file = win->file_info;
  924.    for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  925.       if (wp->file_info == file) {
  926.          if (!wp->visible) {
  927.             if (wp->prev == NULL) {
  928.                if (wp->next == NULL)
  929.                   g_status.stop = TRUE;
  930.                else
  931.                   g_status.window_list = wp->next;
  932.             } else
  933.                wp->prev->next = wp->next;
  934.             if (wp->next)
  935.                wp->next->prev = wp->prev;
  936.             --wp->file_info->ref_count;
  937.             free( wp );
  938.             --g_status.window_count;
  939.          }
  940.       }
  941.    }
  942.  
  943.    if (win->prev == NULL && win->next == NULL)
  944.       g_status.stop = TRUE;
  945.  
  946.    poof = FALSE;
  947.  
  948.    if (g_status.stop != TRUE) {
  949.       /*
  950.        * see if there are any invisible windows with same top and bottom,
  951.        *  lines, and start_col and end_col as this window.  start looking at
  952.        *  end of window list.
  953.        */
  954.       top       = win->top_line;
  955.       bottom    = win->bottom_line;
  956.       start_col = win->start_col;
  957.       end_col   = win->end_col;
  958.       wp = g_status.window_list;
  959.       if (wp != NULL) {
  960.          while (wp->next != NULL)
  961.             wp = wp->next;
  962.       }
  963.       while (wp != NULL && poof == FALSE) {
  964.          if (wp->top_line == top         &&  wp->bottom_line == bottom  &&
  965.              wp->start_col == start_col  &&  wp->end_col == end_col     &&
  966.                                                               !wp->visible)
  967.             poof = TRUE;
  968.          else
  969.             wp = wp->prev;
  970.       }
  971.  
  972.       if (poof == FALSE) {
  973.          /*
  974.           * see if there are any windows above
  975.           */
  976.          wp = g_status.window_list;
  977.          while (wp != NULL && poof == FALSE) {
  978.             if (wp->bottom_line+2 == win->top_line &&
  979.                 wp->start_col     == win->start_col &&
  980.                      wp->end_col       == win->end_col   && wp->visible) {
  981.                poof = TRUE;
  982.                top  = wp->top_line;
  983.             } else
  984.                wp = wp->next;
  985.          }
  986.          if (poof == FALSE) {
  987.             /*
  988.              * see if there are any windows below
  989.              */
  990.             wp = g_status.window_list;
  991.             while (wp != NULL && poof == FALSE) {
  992.                if (wp->top_line-2 == win->bottom_line  &&
  993.                    wp->start_col     == win->start_col &&
  994.                          wp->end_col    == win->end_col   && wp->visible) {
  995.                   poof = TRUE;
  996.                   bottom = wp->bottom_line;
  997.                } else
  998.                   wp = wp->next;
  999.             }
  1000.          }
  1001.          if (poof == FALSE) {
  1002.             /*
  1003.              * see if there are any windows right
  1004.              */
  1005.             wp = g_status.window_list;
  1006.             while (wp != NULL && poof == FALSE) {
  1007.                if (wp->top_line    == win->top_line  &&
  1008.                          wp->bottom_line == win->bottom_line &&
  1009.                          wp->start_col-2 == win->end_col     && wp->visible) {
  1010.                   poof = TRUE;
  1011.                   end_col = wp->end_col;
  1012.                } else
  1013.                   wp = wp->next;
  1014.             }
  1015.          }
  1016.          if (poof == FALSE) {
  1017.             /*
  1018.              * see if there are any windows left
  1019.              */
  1020.             wp = g_status.window_list;
  1021.             while (wp != NULL && poof == FALSE) {
  1022.                if (wp->top_line    == win->top_line  &&
  1023.                    wp->bottom_line == win->bottom_line &&
  1024.                    wp->end_col+2   == win->start_col   && wp->visible) {
  1025.                   poof = TRUE;
  1026.                   start_col = wp->start_col;
  1027.                } else
  1028.                   wp = wp->next;
  1029.             }
  1030.          }
  1031.          if (poof == FALSE) {
  1032.             /*
  1033.              * see if there are any other invisible windows.  start looking
  1034.              *  at the end of the window list.
  1035.              */
  1036.             wp = g_status.window_list;
  1037.             if (wp != NULL) {
  1038.                while (wp->next != NULL)
  1039.                   wp = wp->next;
  1040.             }
  1041.             while (wp != NULL && poof == FALSE) {
  1042.                if (!wp->visible)
  1043.                   poof = TRUE;
  1044.                else
  1045.                   wp = wp->prev;
  1046.             }
  1047.          }
  1048.       }
  1049.       if (poof) {
  1050.          wp->visible = TRUE;
  1051.          cline = wp->cline - (wp->top_line+wp->ruler);
  1052.          wp->top_line = top;
  1053.          wp->bottom_line = bottom;
  1054.          wp->cline = (wp->top_line+wp->ruler) + cline;
  1055.          if (wp->cline > wp->bottom_line)
  1056.             wp->cline = wp->top_line+wp->ruler;
  1057.          wp->start_col = start_col;
  1058.          wp->end_col   = end_col;
  1059.          if (start_col == 0 && end_col == g_display.ncols - 1)
  1060.             wp->vertical = FALSE;
  1061.          else
  1062.             wp->vertical = TRUE;
  1063.          check_virtual_col( wp, wp->rcol, wp->ccol );
  1064.          setup_window( wp );
  1065.          show_window_header( wp );
  1066.          if (wp->vertical)
  1067.             show_vertical_separator( wp );
  1068.  
  1069.          /*
  1070.           * The window above, below, or previously invisible becomes the new
  1071.           *  current window.
  1072.           */
  1073.          g_status.current_window = wp;
  1074.       }
  1075.    }
  1076.  
  1077.    if (!poof && g_status.stop != TRUE)
  1078.       /*
  1079.        * cannot close current window
  1080.        */
  1081.       error( WARNING, win->bottom_line, win7 );
  1082.    else {
  1083.  
  1084.       /*
  1085.        * free unused file memory if necessary
  1086.        */
  1087.       if (--file->ref_count == 0) {
  1088.  
  1089.          /*
  1090.           * if a block is marked, unmark it
  1091.           */
  1092.          if (file == g_status.marked_file) {
  1093.             g_status.marked      = FALSE;
  1094.             g_status.marked_file = NULL;
  1095.          }
  1096.  
  1097.          for (fp=g_status.file_list; fp != NULL; fp=fp->next) {
  1098.             if (fp->file_no > file->file_no)
  1099.                fp->file_no--;
  1100.          }
  1101.          file_change = file->file_no;
  1102.  
  1103.          /*
  1104.           * no window now refers to this file, so remove file from the list
  1105.           */
  1106.          if (file->prev == NULL)
  1107.             g_status.file_list = file->next;
  1108.          else
  1109.             file->prev->next = file->next;
  1110.          if (file->next)
  1111.             file->next->prev = file->prev;
  1112.  
  1113.          /*
  1114.           * free the line pointers, linked list of line pointers, and
  1115.           *  file struc.
  1116.           */
  1117.          ll = file->undo_top;
  1118.          while (ll != NULL) {
  1119.             temp_ll = ll->next;
  1120.             if (ll->line != NULL)
  1121.                my_free( ll->line );
  1122.             my_free( ll );
  1123.             ll = temp_ll;
  1124.          }
  1125.  
  1126.          ll = file->line_list;
  1127.          while (ll != NULL) {
  1128.             temp_ll = ll->next;
  1129.             if (ll->line != NULL)
  1130.                my_free( ll->line );
  1131.             my_free( ll );
  1132.             ll = temp_ll;
  1133.          }
  1134.  
  1135. #if defined( __MSC__ )
  1136.          _fheapmin( );
  1137. #endif
  1138.  
  1139.          free( file );
  1140.          if (--g_status.file_count) {
  1141.             show_file_count( g_status.file_count );
  1142.             show_avail_mem( );
  1143.          }
  1144.       }
  1145.  
  1146.       /*
  1147.        * remove the current window from the window list
  1148.        */
  1149.       if (win->prev == NULL)
  1150.          g_status.window_list = win->next;
  1151.       else
  1152.          win->prev->next = win->next;
  1153.  
  1154.       if (win->next)
  1155.          win->next->prev = win->prev;
  1156.  
  1157.       if (diff.defined  &&  (diff.w1 == win  ||  diff.w2 == win))
  1158.          diff.defined = FALSE;
  1159.  
  1160.       /*
  1161.        * free the memory taken by the window structure
  1162.        */
  1163.       free( win );
  1164.       --g_status.window_count;
  1165.  
  1166.       if (g_status.stop == FALSE) {
  1167.          g_status.current_file = wp->file_info;
  1168.          wp->file_info->dirty = LOCAL;
  1169.          make_ruler( wp );
  1170.          show_ruler( wp );
  1171.          show_window_count( g_status.window_count );
  1172.          if (file_change) {
  1173.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next)
  1174.                if (wp->visible)
  1175.                   show_window_number_letter( wp );
  1176.          } else {
  1177.             max_letter = 0;
  1178.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next) {
  1179.                if (wp->file_info == file) {
  1180.                   if (wp->letter == LAST_WINDOWLETTER) {
  1181.                      max_letter = strlen( windowletters );
  1182.                      break;
  1183.                   } else {
  1184.                      letter_index = strchr( windowletters, wp->letter )
  1185.                                     - windowletters;
  1186.                      if (letter_index > max_letter)
  1187.                         max_letter = letter_index;
  1188.                   }
  1189.                }
  1190.             }
  1191.             if (max_letter < file->next_letter - 1)
  1192.                file->next_letter = max_letter + 1;
  1193.          }
  1194.       }
  1195.    }
  1196.  
  1197.    if (g_status.stop == TRUE) {
  1198.       if (g_status.sas_defined && g_status.sas_arg < g_status.sas_argc) {
  1199.          show_avail_mem( );
  1200.          for (bottom=0; bottom <= g_display.nlines; bottom++)
  1201.             eol_clear( 0, bottom, g_display.text_color );
  1202.          bottom  = g_display.nlines;
  1203.          set_prompt( win18, bottom );
  1204.          top = getkey( );
  1205.          top = getfunc( top );
  1206.          if (top == PullDown) {
  1207.             major_choice = minor_choice = 0;
  1208.             save_screen_line( 0, 0, display_buff );
  1209.             top = lite_bar_menu( &major_choice, &minor_choice );
  1210.             if (top == Rturn) {
  1211.                top = menu[major_choice].minor[minor_choice].minor_func;
  1212.                if (top != RepeatGrep)
  1213.                   top = ERROR;
  1214.             } else
  1215.                top = ERROR;
  1216.             restore_screen_line( 0, 0, display_buff );
  1217.          }
  1218.          eol_clear( 0, bottom, g_display.text_color );
  1219.          if (top == RepeatGrep) {
  1220.             g_status.command = RepeatGrep;
  1221.             g_status.window_list = g_status.current_window = NULL;
  1222.             if (search_and_seize( g_status.window_list ) != ERROR)
  1223.                g_status.stop = FALSE;
  1224.          }
  1225.       }
  1226.    }
  1227. }
  1228.  
  1229.  
  1230. /*
  1231.  * Name:    create_window
  1232.  * Purpose: To allocate space for a new window structure and set up some
  1233.  *           of the relevant fields.
  1234.  * Date:    June 5, 1991
  1235.  * Passed:  window: pointer to window pointer
  1236.  *          top:    the top line of the new window
  1237.  *          bottom: the bottom line of the new window
  1238.  *          start_col:  starting column of window on screen
  1239.  *          end_col:    ending column of window on screen
  1240.  *          file:   the file structure to be associated with the new window
  1241.  * Returns: OK if window could be created
  1242.  *          ERROR if out of memory
  1243.  */
  1244. int  create_window( TDE_WIN **window, int top, int bottom, int start_col,
  1245.                     int end_col, file_infos *file )
  1246. {
  1247. TDE_WIN *wp;            /* temporary variable - use it instead of **window */
  1248. register TDE_WIN *prev;
  1249. int  rc;                /* return code */
  1250.  
  1251.    rc = OK;
  1252.    /*
  1253.     * allocate space for new window structure
  1254.     */
  1255.    if ((*window = (TDE_WIN *)calloc( 1, sizeof(TDE_WIN) )) == NULL) {
  1256.       /*
  1257.        * out of memory
  1258.        */
  1259.       error( WARNING, g_display.nlines, main4 );
  1260.       rc = ERROR;
  1261.    } else {
  1262.  
  1263.      /*
  1264.       * set up appropriate fields
  1265.       */
  1266.       wp              = *window;
  1267.       wp->file_info   = file;
  1268.       wp->top_line    = top+1;
  1269.       wp->bottom_line = bottom;
  1270.       wp->start_col   = start_col;
  1271.       wp->end_col     = end_col;
  1272.       wp->bin_offset  = 0;
  1273.       wp->ruler       = mode.ruler;
  1274.       make_ruler( wp );
  1275.       wp->cline       = wp->top_line + wp->ruler;
  1276.       if (start_col == 0 && end_col == g_display.ncols-1)
  1277.          wp->vertical = FALSE;
  1278.       else
  1279.          wp->vertical = TRUE;
  1280.       wp->prev        = NULL;
  1281.       wp->next        = NULL;
  1282.  
  1283.       setup_window( wp );
  1284.  
  1285.       /*
  1286.        * add window into window list
  1287.        */
  1288.       prev = g_status.current_window;
  1289.       if (prev) {
  1290.          (*window)->prev = prev;
  1291.          if (prev->next)
  1292.             prev->next->prev = *window;
  1293.          (*window)->next = prev->next;
  1294.          prev->next = *window;
  1295.       }
  1296.       if (g_status.window_list == NULL)
  1297.          g_status.window_list = *window;
  1298.  
  1299.       /*
  1300.        * record that another window is referencing this file
  1301.        */
  1302.       ++file->ref_count;
  1303.       file->dirty = LOCAL;
  1304.       ++g_status.window_count;
  1305.    }
  1306.    return( rc );
  1307. }
  1308.