Home | History | Annotate | Line # | Download | only in info
      1  1.2       wiz /*	$NetBSD: display.c,v 1.2 2025/09/30 12:56:02 wiz Exp $	*/
      2  1.1  christos 
      3  1.1  christos /* display.c -- How to display Info windows.
      4  1.1  christos    Id: display.c,v 1.7 2004/04/11 17:56:45 karl Exp
      5  1.1  christos 
      6  1.1  christos    Copyright (C) 1993, 1997, 2003, 2004 Free Software Foundation, Inc.
      7  1.1  christos 
      8  1.1  christos    This program is free software; you can redistribute it and/or modify
      9  1.1  christos    it under the terms of the GNU General Public License as published by
     10  1.1  christos    the Free Software Foundation; either version 2, or (at your option)
     11  1.1  christos    any later version.
     12  1.1  christos 
     13  1.1  christos    This program is distributed in the hope that it will be useful,
     14  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  1.1  christos    GNU General Public License for more details.
     17  1.1  christos 
     18  1.1  christos    You should have received a copy of the GNU General Public License
     19  1.1  christos    along with this program; if not, write to the Free Software
     20  1.1  christos    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     21  1.1  christos 
     22  1.1  christos    Originally written by Brian Fox (bfox (at) ai.mit.edu). */
     23  1.1  christos 
     24  1.1  christos #include "info.h"
     25  1.1  christos #include "display.h"
     26  1.1  christos 
     27  1.1  christos extern int info_any_buffered_input_p (void); /* Found in session.c. */
     28  1.1  christos 
     29  1.1  christos static void free_display (DISPLAY_LINE **display);
     30  1.1  christos static DISPLAY_LINE **make_display (int width, int height);
     31  1.1  christos 
     32  1.1  christos void handle_tag (char *tag);
     33  1.1  christos void handle_tag_start (char *tag);
     34  1.1  christos void handle_tag_end (char *tag);
     35  1.1  christos 
     36  1.1  christos /* An array of display lines which tell us what is currently visible on
     37  1.1  christos    the display.  */
     38  1.1  christos DISPLAY_LINE **the_display = (DISPLAY_LINE **)NULL;
     39  1.1  christos 
     40  1.1  christos /* Non-zero means do no output. */
     41  1.1  christos int display_inhibited = 0;
     42  1.1  christos 
     43  1.1  christos /* Initialize THE_DISPLAY to WIDTH and HEIGHT, with nothing in it. */
     44  1.1  christos void
     45  1.1  christos display_initialize_display (int width, int height)
     46  1.1  christos {
     47  1.1  christos   free_display (the_display);
     48  1.1  christos   the_display = make_display (width, height);
     49  1.1  christos   display_clear_display (the_display);
     50  1.1  christos }
     51  1.1  christos 
     52  1.1  christos /* Clear all of the lines in DISPLAY making the screen blank. */
     53  1.1  christos void
     54  1.1  christos display_clear_display (DISPLAY_LINE **display)
     55  1.1  christos {
     56  1.1  christos   register int i;
     57  1.1  christos 
     58  1.1  christos   for (i = 0; display[i]; i++)
     59  1.1  christos     {
     60  1.1  christos       display[i]->text[0] = '\0';
     61  1.1  christos       display[i]->textlen = 0;
     62  1.1  christos       display[i]->inverse = 0;
     63  1.1  christos     }
     64  1.1  christos }
     65  1.1  christos 
     66  1.1  christos /* Non-zero if we didn't completely redisplay a window. */
     67  1.1  christos int display_was_interrupted_p = 0;
     68  1.1  christos 
     69  1.1  christos /* Update the windows pointed to by WINDOW in the_display.  This actually
     70  1.1  christos    writes the text on the screen. */
     71  1.1  christos void
     72  1.1  christos display_update_display (WINDOW *window)
     73  1.1  christos {
     74  1.1  christos   register WINDOW *win;
     75  1.1  christos 
     76  1.1  christos   display_was_interrupted_p = 0;
     77  1.1  christos 
     78  1.1  christos   /* For every window in the list, check contents against the display. */
     79  1.1  christos   for (win = window; win; win = win->next)
     80  1.1  christos     {
     81  1.1  christos       /* Only re-display visible windows which need updating. */
     82  1.1  christos       if (((win->flags & W_WindowVisible) == 0) ||
     83  1.1  christos           ((win->flags & W_UpdateWindow) == 0) ||
     84  1.1  christos           (win->height == 0))
     85  1.1  christos         continue;
     86  1.1  christos 
     87  1.1  christos       display_update_one_window (win);
     88  1.1  christos       if (display_was_interrupted_p)
     89  1.1  christos         break;
     90  1.1  christos     }
     91  1.1  christos 
     92  1.1  christos   /* Always update the echo area. */
     93  1.1  christos   display_update_one_window (the_echo_area);
     94  1.1  christos }
     95  1.1  christos 
     96  1.1  christos void
     97  1.1  christos handle_tag_start (char *tag)
     98  1.1  christos {
     99  1.1  christos   /* TODO really handle this tag.  */
    100  1.1  christos   return;
    101  1.1  christos }
    102  1.1  christos 
    103  1.1  christos void
    104  1.1  christos handle_tag_end (char *tag)
    105  1.1  christos {
    106  1.1  christos   /* TODO really handle this tag.  */
    107  1.1  christos   return;
    108  1.1  christos }
    109  1.1  christos 
    110  1.1  christos void
    111  1.1  christos handle_tag (char *tag)
    112  1.1  christos {
    113  1.1  christos     if (tag[0] == '/')
    114  1.1  christos       {
    115  1.1  christos 	tag++;
    116  1.1  christos 	handle_tag_end (tag);
    117  1.1  christos       }
    118  1.1  christos     else
    119  1.1  christos       handle_tag_start (tag);
    120  1.1  christos }
    121  1.1  christos 
    122  1.1  christos /* Display WIN on the_display.  Unlike display_update_display (), this
    123  1.1  christos    function only does one window. */
    124  1.1  christos void
    125  1.1  christos display_update_one_window (WINDOW *win)
    126  1.1  christos {
    127  1.1  christos   register char *nodetext;      /* Current character to display. */
    128  1.1  christos   register char *last_node_char; /* Position of the last character in node. */
    129  1.1  christos   register int i;               /* General use index. */
    130  1.1  christos   char *printed_line;           /* Buffer for a printed line. */
    131  1.1  christos   int pl_index = 0;             /* Index into PRINTED_LINE. */
    132  1.1  christos   int line_index = 0;           /* Number of lines done so far. */
    133  1.1  christos   int pl_ignore = 0;		/* How many chars use zero width on screen. */
    134  1.1  christos   int allocated_win_width;
    135  1.1  christos   DISPLAY_LINE **display = the_display;
    136  1.1  christos 
    137  1.1  christos   /* If display is inhibited, that counts as an interrupted display. */
    138  1.1  christos   if (display_inhibited)
    139  1.1  christos     display_was_interrupted_p = 1;
    140  1.1  christos 
    141  1.1  christos   /* If the window has no height, or display is inhibited, quit now. */
    142  1.1  christos   if (!win->height || display_inhibited)
    143  1.1  christos     return;
    144  1.1  christos 
    145  1.1  christos   /* If the window's first row doesn't appear in the_screen, then it
    146  1.1  christos      cannot be displayed.  This can happen when the_echo_area is the
    147  1.1  christos      window to be displayed, and the screen has shrunk to less than one
    148  1.1  christos      line. */
    149  1.1  christos   if ((win->first_row < 0) || (win->first_row > the_screen->height))
    150  1.1  christos     return;
    151  1.1  christos 
    152  1.1  christos   /* Print each line in the window into our local buffer, and then
    153  1.1  christos      check the contents of that buffer against the display.  If they
    154  1.1  christos      differ, update the display. */
    155  1.1  christos   allocated_win_width = win->width + 1;
    156  1.1  christos   printed_line = (char *)xmalloc (allocated_win_width);
    157  1.1  christos 
    158  1.1  christos   if (!win->node || !win->line_starts)
    159  1.1  christos     goto done_with_node_display;
    160  1.1  christos 
    161  1.1  christos   nodetext = win->line_starts[win->pagetop];
    162  1.1  christos   last_node_char = win->node->contents + win->node->nodelen;
    163  1.1  christos 
    164  1.1  christos   for (; nodetext < last_node_char; nodetext++)
    165  1.1  christos     {
    166  1.1  christos       char *rep = NULL, *rep_carried_over, rep_temp[2];
    167  1.1  christos       int replen;
    168  1.1  christos 
    169  1.2       wiz       if (isprint ((unsigned char)*nodetext))
    170  1.1  christos         {
    171  1.1  christos           rep_temp[0] = *nodetext;
    172  1.1  christos           replen = 1;
    173  1.1  christos           rep_temp[1] = '\0';
    174  1.1  christos           rep = rep_temp;
    175  1.1  christos         }
    176  1.1  christos       else
    177  1.1  christos         {
    178  1.1  christos           if (*nodetext == '\r' || *nodetext == '\n')
    179  1.1  christos             {
    180  1.1  christos               replen = win->width - pl_index + pl_ignore;
    181  1.1  christos             }
    182  1.1  christos 	  else if (*nodetext == '\0'
    183  1.1  christos 		   && (nodetext + 2) < last_node_char
    184  1.1  christos 		   && *(nodetext + 1) == '\b'
    185  1.1  christos 		   && *(nodetext + 2) == '[')
    186  1.1  christos 	    {
    187  1.1  christos 	      /* Found new style tag/cookie \0\b[
    188  1.1  christos 		 Read until the closing tag \0\b] */
    189  1.1  christos 	      int element_len = 0;
    190  1.1  christos 	      char *element;
    191  1.1  christos 
    192  1.1  christos 	      /* Skip the escapes.  */
    193  1.1  christos 	      nodetext += 3;
    194  1.1  christos 
    195  1.1  christos 	      while (!(*nodetext == '\0'
    196  1.1  christos 		    && *(nodetext + 1) == '\b'
    197  1.1  christos 		    && *(nodetext + 2) == ']'))
    198  1.1  christos 		{
    199  1.1  christos 		  nodetext++;
    200  1.1  christos 		  element_len++;
    201  1.1  christos 		}
    202  1.1  christos 
    203  1.1  christos 	      element = (char *) malloc (element_len + 1);
    204  1.1  christos 	      strncpy (element, nodetext - element_len, element_len);
    205  1.1  christos 
    206  1.1  christos 	      /* Skip the escapes.  */
    207  1.1  christos 	      nodetext += 2;
    208  1.1  christos 	      pl_ignore += element_len + 5;
    209  1.1  christos 	      /* Append string terminator.  */
    210  1.1  christos 	      element[element_len] = '\0';
    211  1.1  christos 
    212  1.1  christos 	      handle_tag (element);
    213  1.1  christos 
    214  1.1  christos 	      /* Over and out */
    215  1.1  christos 	      free (element);
    216  1.1  christos 
    217  1.1  christos 	      continue;
    218  1.1  christos 	    }
    219  1.1  christos           else
    220  1.1  christos             {
    221  1.1  christos               rep = printed_representation (*nodetext, pl_index);
    222  1.1  christos               replen = strlen (rep);
    223  1.1  christos             }
    224  1.1  christos         }
    225  1.1  christos 
    226  1.1  christos       /* Support ANSI escape sequences under -R.  */
    227  1.1  christos       if (raw_escapes_p
    228  1.1  christos 	  && *nodetext == '\033'
    229  1.1  christos 	  && nodetext[1] == '['
    230  1.1  christos 	  && isdigit (nodetext[2]))
    231  1.1  christos 	{
    232  1.1  christos 	  if (nodetext[3] == 'm')
    233  1.1  christos 	    pl_ignore += 4;
    234  1.1  christos 	  else if (isdigit (nodetext[3]) && nodetext[4] == 'm')
    235  1.1  christos 	    pl_ignore += 5;
    236  1.1  christos 	}
    237  1.1  christos       while (pl_index + 2 >= allocated_win_width - 1)
    238  1.1  christos 	{
    239  1.1  christos 	  allocated_win_width *= 2;
    240  1.1  christos 	  printed_line = (char *)xrealloc (printed_line, allocated_win_width);
    241  1.1  christos 	}
    242  1.1  christos 
    243  1.1  christos       /* If this character can be printed without passing the width of
    244  1.1  christos          the line, then stuff it into the line. */
    245  1.1  christos       if (replen + pl_index < win->width + pl_ignore)
    246  1.1  christos         {
    247  1.1  christos           /* Optimize if possible. */
    248  1.1  christos           if (replen == 1)
    249  1.1  christos             {
    250  1.1  christos               printed_line[pl_index++] = *rep;
    251  1.1  christos             }
    252  1.1  christos           else
    253  1.1  christos             {
    254  1.1  christos               for (i = 0; i < replen; i++)
    255  1.1  christos                 printed_line[pl_index++] = rep[i];
    256  1.1  christos             }
    257  1.1  christos         }
    258  1.1  christos       else
    259  1.1  christos         {
    260  1.1  christos           DISPLAY_LINE *entry;
    261  1.1  christos 
    262  1.1  christos           /* If this character cannot be printed in this line, we have
    263  1.1  christos              found the end of this line as it would appear on the screen.
    264  1.1  christos              Carefully print the end of the line, and then compare. */
    265  1.1  christos           if (*nodetext == '\n' || *nodetext == '\r' || *nodetext == '\t')
    266  1.1  christos             {
    267  1.1  christos               printed_line[pl_index] = '\0';
    268  1.1  christos               rep_carried_over = (char *)NULL;
    269  1.1  christos             }
    270  1.1  christos           else
    271  1.1  christos             {
    272  1.1  christos               /* The printed representation of this character extends into
    273  1.1  christos                  the next line.  Remember the offset of the last character
    274  1.1  christos                  printed out of REP so that we can carry the character over
    275  1.1  christos                  to the next line. */
    276  1.1  christos               for (i = 0; pl_index < (win->width + pl_ignore - 1);)
    277  1.1  christos                 printed_line[pl_index++] = rep[i++];
    278  1.1  christos 
    279  1.1  christos               rep_carried_over = rep + i;
    280  1.1  christos 
    281  1.1  christos               /* If printing the last character in this window couldn't
    282  1.1  christos                  possibly cause the screen to scroll, place a backslash
    283  1.1  christos                  in the rightmost column. */
    284  1.1  christos               if (1 + line_index + win->first_row < the_screen->height)
    285  1.1  christos                 {
    286  1.1  christos                   if (win->flags & W_NoWrap)
    287  1.1  christos                     printed_line[pl_index++] = '$';
    288  1.1  christos                   else
    289  1.1  christos                     printed_line[pl_index++] = '\\';
    290  1.1  christos                 }
    291  1.1  christos               printed_line[pl_index] = '\0';
    292  1.1  christos             }
    293  1.1  christos 
    294  1.1  christos           /* We have the exact line as it should appear on the screen.
    295  1.1  christos              Check to see if this line matches the one already appearing
    296  1.1  christos              on the screen. */
    297  1.1  christos           entry = display[line_index + win->first_row];
    298  1.1  christos 
    299  1.1  christos           /* If the screen line is inversed, then we have to clear
    300  1.1  christos              the line from the screen first.  Why, I don't know.
    301  1.1  christos              (But don't do this if we have no visible entries, as can
    302  1.1  christos              happen if the window is shrunk very small.)  */
    303  1.1  christos           if ((entry && entry->inverse)
    304  1.1  christos 	      /* Need to erase the line if it has escape sequences.  */
    305  1.1  christos 	      || (raw_escapes_p && strchr (entry->text, '\033') != 0))
    306  1.1  christos             {
    307  1.1  christos               terminal_goto_xy (0, line_index + win->first_row);
    308  1.1  christos               terminal_clear_to_eol ();
    309  1.1  christos               entry->inverse = 0;
    310  1.1  christos               entry->text[0] = '\0';
    311  1.1  christos               entry->textlen = 0;
    312  1.1  christos             }
    313  1.1  christos 
    314  1.1  christos           /* Find the offset where these lines differ. */
    315  1.1  christos           for (i = 0; i < pl_index; i++)
    316  1.1  christos             if (printed_line[i] != entry->text[i])
    317  1.1  christos               break;
    318  1.1  christos 
    319  1.1  christos           /* If the lines are not the same length, or if they differed
    320  1.1  christos              at all, we must do some redrawing. */
    321  1.1  christos           if ((i != pl_index) || (pl_index != entry->textlen))
    322  1.1  christos             {
    323  1.1  christos               /* Move to the proper point on the terminal. */
    324  1.1  christos               terminal_goto_xy (i, line_index + win->first_row);
    325  1.1  christos 
    326  1.1  christos               /* If there is any text to print, print it. */
    327  1.1  christos               if (i != pl_index)
    328  1.1  christos                 terminal_put_text (printed_line + i);
    329  1.1  christos 
    330  1.1  christos               /* If the printed text didn't extend all the way to the edge
    331  1.1  christos                  of the window, and text was appearing between here and the
    332  1.1  christos                  edge of the window, clear from here to the end of the line. */
    333  1.1  christos               if ((pl_index < win->width + pl_ignore
    334  1.1  christos 		   && pl_index < entry->textlen)
    335  1.1  christos 		  || (entry->inverse))
    336  1.1  christos                 terminal_clear_to_eol ();
    337  1.1  christos 
    338  1.1  christos               fflush (stdout);
    339  1.1  christos 
    340  1.1  christos               /* Update the display text buffer. */
    341  1.1  christos 	      if (strlen (printed_line) > (unsigned int) screenwidth)
    342  1.1  christos 		/* printed_line[] can include more than screenwidth
    343  1.1  christos 		   characters if we are under -R and there are escape
    344  1.1  christos 		   sequences in it.  However, entry->text was
    345  1.1  christos 		   allocated (in display_initialize_display) for
    346  1.1  christos 		   screenwidth characters only.  */
    347  1.1  christos 		entry->text = xrealloc (entry->text, strlen (printed_line)+1);
    348  1.1  christos               strcpy (entry->text + i, printed_line + i);
    349  1.1  christos               entry->textlen = pl_index;
    350  1.1  christos 
    351  1.1  christos               /* Lines showing node text are not in inverse.  Only modelines
    352  1.1  christos                  have that distinction. */
    353  1.1  christos               entry->inverse = 0;
    354  1.1  christos             }
    355  1.1  christos 
    356  1.1  christos           /* We have done at least one line.  Increment our screen line
    357  1.1  christos              index, and check against the bottom of the window. */
    358  1.1  christos           if (++line_index == win->height)
    359  1.1  christos             break;
    360  1.1  christos 
    361  1.1  christos           /* A line has been displayed, and the screen reflects that state.
    362  1.1  christos              If there is typeahead pending, then let that typeahead be read
    363  1.1  christos              now, instead of continuing with the display. */
    364  1.1  christos           if (info_any_buffered_input_p ())
    365  1.1  christos             {
    366  1.1  christos               free (printed_line);
    367  1.1  christos               display_was_interrupted_p = 1;
    368  1.1  christos               return;
    369  1.1  christos             }
    370  1.1  christos 
    371  1.1  christos           /* Reset PL_INDEX to the start of the line. */
    372  1.1  christos           pl_index = 0;
    373  1.1  christos 	  pl_ignore = 0;	/* this is computed per line */
    374  1.1  christos 
    375  1.1  christos           /* If there are characters from REP left to print, stuff them
    376  1.1  christos              into the buffer now. */
    377  1.1  christos           if (rep_carried_over)
    378  1.1  christos             for (; rep[pl_index]; pl_index++)
    379  1.1  christos               printed_line[pl_index] = rep[pl_index];
    380  1.1  christos 
    381  1.1  christos           /* If this window has chosen not to wrap lines, skip to the end
    382  1.1  christos              of the physical line in the buffer, and start a new line here. */
    383  1.1  christos           if (pl_index && (win->flags & W_NoWrap))
    384  1.1  christos             {
    385  1.1  christos               char *begin;
    386  1.1  christos 
    387  1.1  christos               pl_index = 0;
    388  1.1  christos               printed_line[0] = '\0';
    389  1.1  christos 
    390  1.1  christos               begin = nodetext;
    391  1.1  christos 
    392  1.1  christos               while ((nodetext < last_node_char) && (*nodetext != '\n'))
    393  1.1  christos                 nodetext++;
    394  1.1  christos             }
    395  1.1  christos         }
    396  1.1  christos     }
    397  1.1  christos 
    398  1.1  christos  done_with_node_display:
    399  1.1  christos   /* We have reached the end of the node or the end of the window.  If it
    400  1.1  christos      is the end of the node, then clear the lines of the window from here
    401  1.1  christos      to the end of the window. */
    402  1.1  christos   for (; line_index < win->height; line_index++)
    403  1.1  christos     {
    404  1.1  christos       DISPLAY_LINE *entry = display[line_index + win->first_row];
    405  1.1  christos 
    406  1.1  christos       /* If this line has text on it then make it go away. */
    407  1.1  christos       if (entry && entry->textlen)
    408  1.1  christos         {
    409  1.1  christos           entry->textlen = 0;
    410  1.1  christos           entry->text[0] = '\0';
    411  1.1  christos 
    412  1.1  christos           terminal_goto_xy (0, line_index + win->first_row);
    413  1.1  christos           terminal_clear_to_eol ();
    414  1.1  christos         }
    415  1.1  christos     }
    416  1.1  christos 
    417  1.1  christos   /* Finally, if this window has a modeline it might need to be redisplayed.
    418  1.1  christos      Check the window's modeline against the one in the display, and update
    419  1.1  christos      if necessary. */
    420  1.1  christos   if ((win->flags & W_InhibitMode) == 0)
    421  1.1  christos     {
    422  1.1  christos       window_make_modeline (win);
    423  1.1  christos       line_index = win->first_row + win->height;
    424  1.1  christos 
    425  1.1  christos       /* This display line must both be in inverse, and have the same
    426  1.1  christos          contents. */
    427  1.1  christos       if ((!display[line_index]->inverse) ||
    428  1.1  christos           (strcmp (display[line_index]->text, win->modeline) != 0))
    429  1.1  christos         {
    430  1.1  christos           terminal_goto_xy (0, line_index);
    431  1.1  christos           terminal_begin_inverse ();
    432  1.1  christos           terminal_put_text (win->modeline);
    433  1.1  christos           terminal_end_inverse ();
    434  1.1  christos           strcpy (display[line_index]->text, win->modeline);
    435  1.1  christos           display[line_index]->inverse = 1;
    436  1.1  christos           display[line_index]->textlen = strlen (win->modeline);
    437  1.1  christos           fflush (stdout);
    438  1.1  christos         }
    439  1.1  christos     }
    440  1.1  christos 
    441  1.1  christos   /* Okay, this window doesn't need updating anymore. */
    442  1.1  christos   win->flags &= ~W_UpdateWindow;
    443  1.1  christos   free (printed_line);
    444  1.1  christos   fflush (stdout);
    445  1.1  christos }
    446  1.1  christos 
    447  1.1  christos /* Scroll the region of the_display starting at START, ending at END, and
    448  1.1  christos    moving the lines AMOUNT lines.  If AMOUNT is less than zero, the lines
    449  1.1  christos    are moved up in the screen, otherwise down.  Actually, it is possible
    450  1.1  christos    for no scrolling to take place in the case that the terminal doesn't
    451  1.1  christos    support it.  This doesn't matter to us. */
    452  1.1  christos void
    453  1.1  christos display_scroll_display (int start, int end, int amount)
    454  1.1  christos {
    455  1.1  christos   register int i, last;
    456  1.1  christos   DISPLAY_LINE *temp;
    457  1.1  christos 
    458  1.1  christos   /* If this terminal cannot do scrolling, give up now. */
    459  1.1  christos   if (!terminal_can_scroll)
    460  1.1  christos     return;
    461  1.1  christos 
    462  1.1  christos   /* If there isn't anything displayed on the screen because it is too
    463  1.1  christos      small, quit now. */
    464  1.1  christos   if (!the_display[0])
    465  1.1  christos     return;
    466  1.1  christos 
    467  1.1  christos   /* If there is typeahead pending, then don't actually do any scrolling. */
    468  1.1  christos   if (info_any_buffered_input_p ())
    469  1.1  christos     return;
    470  1.1  christos 
    471  1.1  christos   /* Do it on the screen. */
    472  1.1  christos   terminal_scroll_terminal (start, end, amount);
    473  1.1  christos 
    474  1.1  christos   /* Now do it in the display buffer so our contents match the screen. */
    475  1.1  christos   if (amount > 0)
    476  1.1  christos     {
    477  1.1  christos       last = end + amount;
    478  1.1  christos 
    479  1.1  christos       /* Shift the lines to scroll right into place. */
    480  1.1  christos       for (i = 0; i < (end - start); i++)
    481  1.1  christos         {
    482  1.1  christos           temp = the_display[last - i];
    483  1.1  christos           the_display[last - i] = the_display[end - i];
    484  1.1  christos           the_display[end - i] = temp;
    485  1.1  christos         }
    486  1.1  christos 
    487  1.1  christos       /* The lines have been shifted down in the buffer.  Clear all of the
    488  1.1  christos          lines that were vacated. */
    489  1.1  christos       for (i = start; i != (start + amount); i++)
    490  1.1  christos         {
    491  1.1  christos           the_display[i]->text[0] = '\0';
    492  1.1  christos           the_display[i]->textlen = 0;
    493  1.1  christos           the_display[i]->inverse = 0;
    494  1.1  christos         }
    495  1.1  christos     }
    496  1.1  christos 
    497  1.1  christos   if (amount < 0)
    498  1.1  christos     {
    499  1.1  christos       last = start + amount;
    500  1.1  christos       for (i = 0; i < (end - start); i++)
    501  1.1  christos         {
    502  1.1  christos           temp = the_display[last + i];
    503  1.1  christos           the_display[last + i] = the_display[start + i];
    504  1.1  christos           the_display[start + i] = temp;
    505  1.1  christos         }
    506  1.1  christos 
    507  1.1  christos       /* The lines have been shifted up in the buffer.  Clear all of the
    508  1.1  christos          lines that are left over. */
    509  1.1  christos       for (i = end + amount; i != end; i++)
    510  1.1  christos         {
    511  1.1  christos           the_display[i]->text[0] = '\0';
    512  1.1  christos           the_display[i]->textlen = 0;
    513  1.1  christos           the_display[i]->inverse = 0;
    514  1.1  christos         }
    515  1.1  christos     }
    516  1.1  christos }
    517  1.1  christos 
    518  1.1  christos /* Try to scroll lines in WINDOW.  OLD_PAGETOP is the pagetop of WINDOW before
    519  1.1  christos    having had its line starts recalculated.  OLD_STARTS is the list of line
    520  1.1  christos    starts that used to appear in this window.  OLD_COUNT is the number of lines
    521  1.1  christos    that appear in the OLD_STARTS array. */
    522  1.1  christos void
    523  1.1  christos display_scroll_line_starts (WINDOW *window, int old_pagetop,
    524  1.1  christos     char **old_starts, int old_count)
    525  1.1  christos {
    526  1.1  christos   register int i, old, new;     /* Indices into the line starts arrays. */
    527  1.1  christos   int last_new, last_old;       /* Index of the last visible line. */
    528  1.1  christos   int old_first, new_first;     /* Index of the first changed line. */
    529  1.1  christos   int unchanged_at_top = 0;
    530  1.1  christos   int already_scrolled = 0;
    531  1.1  christos 
    532  1.1  christos   /* Locate the first line which was displayed on the old window. */
    533  1.1  christos   old_first = old_pagetop;
    534  1.1  christos   new_first = window->pagetop;
    535  1.1  christos 
    536  1.1  christos   /* Find the last line currently visible in this window. */
    537  1.1  christos   last_new = window->pagetop + (window->height - 1);
    538  1.1  christos   if (last_new > window->line_count)
    539  1.1  christos     last_new = window->line_count - 1;
    540  1.1  christos 
    541  1.1  christos   /* Find the last line which used to be currently visible in this window. */
    542  1.1  christos   last_old = old_pagetop + (window->height - 1);
    543  1.1  christos   if (last_old > old_count)
    544  1.1  christos     last_old = old_count - 1;
    545  1.1  christos 
    546  1.1  christos   for (old = old_first, new = new_first;
    547  1.1  christos        old < last_old && new < last_new;
    548  1.1  christos        old++, new++)
    549  1.1  christos     if (old_starts[old] != window->line_starts[new])
    550  1.1  christos       break;
    551  1.1  christos     else
    552  1.1  christos       unchanged_at_top++;
    553  1.1  christos 
    554  1.1  christos   /* Loop through the old lines looking for a match in the new lines. */
    555  1.1  christos   for (old = old_first + unchanged_at_top; old < last_old; old++)
    556  1.1  christos     {
    557  1.1  christos       for (new = new_first; new < last_new; new++)
    558  1.1  christos         if (old_starts[old] == window->line_starts[new])
    559  1.1  christos           {
    560  1.1  christos             /* Find the extent of the matching lines. */
    561  1.1  christos             for (i = 0; (old + i) < last_old; i++)
    562  1.1  christos               if (old_starts[old + i] != window->line_starts[new + i])
    563  1.1  christos                 break;
    564  1.1  christos 
    565  1.1  christos             /* Scroll these lines if there are enough of them. */
    566  1.1  christos             {
    567  1.1  christos               int start, end, amount;
    568  1.1  christos 
    569  1.1  christos               start = (window->first_row
    570  1.1  christos                        + ((old + already_scrolled) - old_pagetop));
    571  1.1  christos               amount = new - (old + already_scrolled);
    572  1.1  christos               end = window->first_row + window->height;
    573  1.1  christos 
    574  1.1  christos               /* If we are shifting the block of lines down, then the last
    575  1.1  christos                  AMOUNT lines will become invisible.  Thus, don't bother
    576  1.1  christos                  scrolling them. */
    577  1.1  christos               if (amount > 0)
    578  1.1  christos                 end -= amount;
    579  1.1  christos 
    580  1.1  christos               if ((end - start) > 0)
    581  1.1  christos                 {
    582  1.1  christos                   display_scroll_display (start, end, amount);
    583  1.1  christos 
    584  1.1  christos                   /* Some lines have been scrolled.  Simulate the scrolling
    585  1.1  christos                      by offsetting the value of the old index. */
    586  1.1  christos                   old += i;
    587  1.1  christos                   already_scrolled += amount;
    588  1.1  christos                 }
    589  1.1  christos             }
    590  1.1  christos           }
    591  1.1  christos     }
    592  1.1  christos }
    593  1.1  christos 
    594  1.1  christos /* Move the screen cursor to directly over the current character in WINDOW. */
    595  1.1  christos void
    596  1.1  christos display_cursor_at_point (WINDOW *window)
    597  1.1  christos {
    598  1.1  christos   int vpos, hpos;
    599  1.1  christos 
    600  1.1  christos   vpos = window_line_of_point (window) - window->pagetop + window->first_row;
    601  1.1  christos   hpos = window_get_cursor_column (window);
    602  1.1  christos   terminal_goto_xy (hpos, vpos);
    603  1.1  christos   fflush (stdout);
    604  1.1  christos }
    605  1.1  christos 
    606  1.1  christos /* **************************************************************** */
    608  1.1  christos /*                                                                  */
    609  1.1  christos /*                   Functions Static to this File                  */
    610  1.1  christos /*                                                                  */
    611  1.1  christos /* **************************************************************** */
    612  1.1  christos 
    613  1.1  christos /* Make a DISPLAY_LINE ** with width and height. */
    614  1.1  christos static DISPLAY_LINE **
    615  1.1  christos make_display (int width, int height)
    616  1.1  christos {
    617  1.1  christos   register int i;
    618  1.1  christos   DISPLAY_LINE **display;
    619  1.1  christos 
    620  1.1  christos   display = (DISPLAY_LINE **)xmalloc ((1 + height) * sizeof (DISPLAY_LINE *));
    621  1.1  christos 
    622  1.1  christos   for (i = 0; i < height; i++)
    623  1.1  christos     {
    624  1.1  christos       display[i] = (DISPLAY_LINE *)xmalloc (sizeof (DISPLAY_LINE));
    625  1.1  christos       display[i]->text = (char *)xmalloc (1 + width);
    626  1.1  christos       display[i]->textlen = 0;
    627  1.1  christos       display[i]->inverse = 0;
    628  1.1  christos     }
    629  1.1  christos   display[i] = (DISPLAY_LINE *)NULL;
    630  1.1  christos   return (display);
    631  1.1  christos }
    632  1.1  christos 
    633  1.1  christos /* Free the storage allocated to DISPLAY. */
    634  1.1  christos static void
    635  1.1  christos free_display (DISPLAY_LINE **display)
    636  1.1  christos {
    637  1.1  christos   register int i;
    638  1.1  christos   register DISPLAY_LINE *display_line;
    639  1.1  christos 
    640  1.1  christos   if (!display)
    641  1.1  christos     return;
    642  1.1  christos 
    643  1.1  christos   for (i = 0; (display_line = display[i]); i++)
    644  1.1  christos     {
    645  1.1  christos       free (display_line->text);
    646  1.1  christos       free (display_line);
    647  1.1  christos     }
    648  1.1  christos   free (display);
    649                }
    650