142660Smarkm/* display.c -- How to display Info windows.
2146515Sru   $Id: display.c,v 1.7 2004/04/11 17:56:45 karl Exp $
321495Sjmacd
4146515Sru   Copyright (C) 1993, 1997, 2003, 2004 Free Software Foundation, Inc.
521495Sjmacd
621495Sjmacd   This program is free software; you can redistribute it and/or modify
721495Sjmacd   it under the terms of the GNU General Public License as published by
821495Sjmacd   the Free Software Foundation; either version 2, or (at your option)
921495Sjmacd   any later version.
1021495Sjmacd
1121495Sjmacd   This program is distributed in the hope that it will be useful,
1221495Sjmacd   but WITHOUT ANY WARRANTY; without even the implied warranty of
1321495Sjmacd   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1421495Sjmacd   GNU General Public License for more details.
1521495Sjmacd
1621495Sjmacd   You should have received a copy of the GNU General Public License
1721495Sjmacd   along with this program; if not, write to the Free Software
1821495Sjmacd   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1921495Sjmacd
20146515Sru   Originally written by Brian Fox (bfox@ai.mit.edu). */
2121495Sjmacd
2242660Smarkm#include "info.h"
2321495Sjmacd#include "display.h"
2421495Sjmacd
25146515Sruextern int info_any_buffered_input_p (void); /* Found in session.c. */
2621495Sjmacd
27146515Srustatic void free_display (DISPLAY_LINE **display);
28146515Srustatic DISPLAY_LINE **make_display (int width, int height);
2921495Sjmacd
30146515Sruvoid handle_tag (char *tag);
31146515Sruvoid handle_tag_start (char *tag);
32146515Sruvoid handle_tag_end (char *tag);
33146515Sru
3421495Sjmacd/* An array of display lines which tell us what is currently visible on
3521495Sjmacd   the display.  */
3621495SjmacdDISPLAY_LINE **the_display = (DISPLAY_LINE **)NULL;
3721495Sjmacd
3821495Sjmacd/* Non-zero means do no output. */
3921495Sjmacdint display_inhibited = 0;
4021495Sjmacd
4121495Sjmacd/* Initialize THE_DISPLAY to WIDTH and HEIGHT, with nothing in it. */
4221495Sjmacdvoid
43146515Srudisplay_initialize_display (int width, int height)
4421495Sjmacd{
4521495Sjmacd  free_display (the_display);
4621495Sjmacd  the_display = make_display (width, height);
4721495Sjmacd  display_clear_display (the_display);
4821495Sjmacd}
4921495Sjmacd
5021495Sjmacd/* Clear all of the lines in DISPLAY making the screen blank. */
5121495Sjmacdvoid
52146515Srudisplay_clear_display (DISPLAY_LINE **display)
5321495Sjmacd{
5421495Sjmacd  register int i;
5521495Sjmacd
56146515Sru  for (i = 0; display[i]; i++)
5721495Sjmacd    {
5821495Sjmacd      display[i]->text[0] = '\0';
5921495Sjmacd      display[i]->textlen = 0;
6021495Sjmacd      display[i]->inverse = 0;
6121495Sjmacd    }
6221495Sjmacd}
6321495Sjmacd
6421495Sjmacd/* Non-zero if we didn't completely redisplay a window. */
6521495Sjmacdint display_was_interrupted_p = 0;
6621495Sjmacd
6721495Sjmacd/* Update the windows pointed to by WINDOW in the_display.  This actually
6821495Sjmacd   writes the text on the screen. */
6921495Sjmacdvoid
70146515Srudisplay_update_display (WINDOW *window)
7121495Sjmacd{
7221495Sjmacd  register WINDOW *win;
7321495Sjmacd
7421495Sjmacd  display_was_interrupted_p = 0;
7521495Sjmacd
7621495Sjmacd  /* For every window in the list, check contents against the display. */
7721495Sjmacd  for (win = window; win; win = win->next)
7821495Sjmacd    {
7921495Sjmacd      /* Only re-display visible windows which need updating. */
8021495Sjmacd      if (((win->flags & W_WindowVisible) == 0) ||
8142660Smarkm          ((win->flags & W_UpdateWindow) == 0) ||
8242660Smarkm          (win->height == 0))
8342660Smarkm        continue;
8421495Sjmacd
8521495Sjmacd      display_update_one_window (win);
8621495Sjmacd      if (display_was_interrupted_p)
8742660Smarkm        break;
8821495Sjmacd    }
8921495Sjmacd
9021495Sjmacd  /* Always update the echo area. */
9121495Sjmacd  display_update_one_window (the_echo_area);
9221495Sjmacd}
9321495Sjmacd
94146515Sruvoid
95146515Sruhandle_tag_start (char *tag)
96146515Sru{
97146515Sru  /* TODO really handle this tag.  */
98146515Sru  return;
99146515Sru}
100146515Sru
101146515Sruvoid
102146515Sruhandle_tag_end (char *tag)
103146515Sru{
104146515Sru  /* TODO really handle this tag.  */
105146515Sru  return;
106146515Sru}
107146515Sru
108146515Sruvoid
109146515Sruhandle_tag (char *tag)
110146515Sru{
111146515Sru    if (tag[0] == '/')
112146515Sru      {
113146515Sru	tag++;
114146515Sru	handle_tag_end (tag);
115146515Sru      }
116146515Sru    else
117146515Sru      handle_tag_start (tag);
118146515Sru}
119146515Sru
12021495Sjmacd/* Display WIN on the_display.  Unlike display_update_display (), this
12121495Sjmacd   function only does one window. */
12221495Sjmacdvoid
123146515Srudisplay_update_one_window (WINDOW *win)
12421495Sjmacd{
12542660Smarkm  register char *nodetext;      /* Current character to display. */
12621495Sjmacd  register char *last_node_char; /* Position of the last character in node. */
12742660Smarkm  register int i;               /* General use index. */
12842660Smarkm  char *printed_line;           /* Buffer for a printed line. */
12942660Smarkm  int pl_index = 0;             /* Index into PRINTED_LINE. */
13042660Smarkm  int line_index = 0;           /* Number of lines done so far. */
131100513Sru  int pl_ignore = 0;		/* How many chars use zero width on screen. */
132100513Sru  int allocated_win_width;
13321495Sjmacd  DISPLAY_LINE **display = the_display;
13421495Sjmacd
13521495Sjmacd  /* If display is inhibited, that counts as an interrupted display. */
13621495Sjmacd  if (display_inhibited)
13721495Sjmacd    display_was_interrupted_p = 1;
13821495Sjmacd
13921495Sjmacd  /* If the window has no height, or display is inhibited, quit now. */
14021495Sjmacd  if (!win->height || display_inhibited)
14121495Sjmacd    return;
14221495Sjmacd
14321495Sjmacd  /* If the window's first row doesn't appear in the_screen, then it
14421495Sjmacd     cannot be displayed.  This can happen when the_echo_area is the
14521495Sjmacd     window to be displayed, and the screen has shrunk to less than one
14621495Sjmacd     line. */
14721495Sjmacd  if ((win->first_row < 0) || (win->first_row > the_screen->height))
14821495Sjmacd    return;
14921495Sjmacd
15021495Sjmacd  /* Print each line in the window into our local buffer, and then
15121495Sjmacd     check the contents of that buffer against the display.  If they
15221495Sjmacd     differ, update the display. */
153100513Sru  allocated_win_width = win->width + 1;
154100513Sru  printed_line = (char *)xmalloc (allocated_win_width);
15521495Sjmacd
15621495Sjmacd  if (!win->node || !win->line_starts)
15721495Sjmacd    goto done_with_node_display;
15821495Sjmacd
15921495Sjmacd  nodetext = win->line_starts[win->pagetop];
16021495Sjmacd  last_node_char = win->node->contents + win->node->nodelen;
16121495Sjmacd
16221495Sjmacd  for (; nodetext < last_node_char; nodetext++)
16321495Sjmacd    {
164116525Sru      char *rep = NULL, *rep_carried_over, rep_temp[2];
16521495Sjmacd      int replen;
16621495Sjmacd
16721495Sjmacd      if (isprint (*nodetext))
16842660Smarkm        {
16942660Smarkm          rep_temp[0] = *nodetext;
17042660Smarkm          replen = 1;
17142660Smarkm          rep_temp[1] = '\0';
17242660Smarkm          rep = rep_temp;
17342660Smarkm        }
17421495Sjmacd      else
17542660Smarkm        {
17642660Smarkm          if (*nodetext == '\r' || *nodetext == '\n')
17742660Smarkm            {
178100513Sru              replen = win->width - pl_index + pl_ignore;
17942660Smarkm            }
180116525Sru	  else if (*nodetext == '\0'
181146515Sru		   && (nodetext + 2) < last_node_char
182146515Sru		   && *(nodetext + 1) == '\b'
183146515Sru		   && *(nodetext + 2) == '[')
184116525Sru	    {
185146515Sru	      /* Found new style tag/cookie \0\b[
186146515Sru		 Read until the closing tag \0\b] */
187146515Sru	      int element_len = 0;
188146515Sru	      char *element;
189146515Sru
190146515Sru	      /* Skip the escapes.  */
191146515Sru	      nodetext += 3;
192146515Sru
193146515Sru	      while (!(*nodetext == '\0'
194146515Sru		    && *(nodetext + 1) == '\b'
195146515Sru		    && *(nodetext + 2) == ']'))
196146515Sru		{
197146515Sru		  nodetext++;
198146515Sru		  element_len++;
199146515Sru		}
200146515Sru
201146515Sru	      element = (char *) malloc (element_len + 1);
202146515Sru	      strncpy (element, nodetext - element_len, element_len);
203146515Sru
204146515Sru	      /* Skip the escapes.  */
205146515Sru	      nodetext += 2;
206146515Sru	      pl_ignore += element_len + 5;
207146515Sru	      /* Append string terminator.  */
208146515Sru	      element[element_len] = '\0';
209146515Sru
210146515Sru	      handle_tag (element);
211146515Sru
212146515Sru	      /* Over and out */
213146515Sru	      free (element);
214146515Sru
215116525Sru	      continue;
216116525Sru	    }
21742660Smarkm          else
21842660Smarkm            {
21942660Smarkm              rep = printed_representation (*nodetext, pl_index);
22042660Smarkm              replen = strlen (rep);
22142660Smarkm            }
22242660Smarkm        }
22321495Sjmacd
224100513Sru      /* Support ANSI escape sequences under -R.  */
225100513Sru      if (raw_escapes_p
226100513Sru	  && *nodetext == '\033'
227100513Sru	  && nodetext[1] == '['
228100513Sru	  && isdigit (nodetext[2]))
229100513Sru	{
230100513Sru	  if (nodetext[3] == 'm')
231100513Sru	    pl_ignore += 4;
232100513Sru	  else if (isdigit (nodetext[3]) && nodetext[4] == 'm')
233100513Sru	    pl_ignore += 5;
234100513Sru	}
235100513Sru      while (pl_index + 2 >= allocated_win_width - 1)
236100513Sru	{
237100513Sru	  allocated_win_width *= 2;
238100513Sru	  printed_line = (char *)xrealloc (printed_line, allocated_win_width);
239100513Sru	}
240100513Sru
24121495Sjmacd      /* If this character can be printed without passing the width of
24242660Smarkm         the line, then stuff it into the line. */
243100513Sru      if (replen + pl_index < win->width + pl_ignore)
24442660Smarkm        {
24542660Smarkm          /* Optimize if possible. */
24642660Smarkm          if (replen == 1)
24742660Smarkm            {
24842660Smarkm              printed_line[pl_index++] = *rep;
24942660Smarkm            }
25042660Smarkm          else
25142660Smarkm            {
25242660Smarkm              for (i = 0; i < replen; i++)
25342660Smarkm                printed_line[pl_index++] = rep[i];
25442660Smarkm            }
25542660Smarkm        }
25621495Sjmacd      else
25742660Smarkm        {
25842660Smarkm          DISPLAY_LINE *entry;
25921495Sjmacd
26042660Smarkm          /* If this character cannot be printed in this line, we have
26142660Smarkm             found the end of this line as it would appear on the screen.
26242660Smarkm             Carefully print the end of the line, and then compare. */
26342660Smarkm          if (*nodetext == '\n' || *nodetext == '\r' || *nodetext == '\t')
26442660Smarkm            {
26542660Smarkm              printed_line[pl_index] = '\0';
26642660Smarkm              rep_carried_over = (char *)NULL;
26742660Smarkm            }
26842660Smarkm          else
26942660Smarkm            {
27042660Smarkm              /* The printed representation of this character extends into
27142660Smarkm                 the next line.  Remember the offset of the last character
27242660Smarkm                 printed out of REP so that we can carry the character over
27342660Smarkm                 to the next line. */
274100513Sru              for (i = 0; pl_index < (win->width + pl_ignore - 1);)
27542660Smarkm                printed_line[pl_index++] = rep[i++];
276116525Sru
27742660Smarkm              rep_carried_over = rep + i;
27821495Sjmacd
27942660Smarkm              /* If printing the last character in this window couldn't
28042660Smarkm                 possibly cause the screen to scroll, place a backslash
28142660Smarkm                 in the rightmost column. */
28242660Smarkm              if (1 + line_index + win->first_row < the_screen->height)
28342660Smarkm                {
28442660Smarkm                  if (win->flags & W_NoWrap)
28542660Smarkm                    printed_line[pl_index++] = '$';
28642660Smarkm                  else
28742660Smarkm                    printed_line[pl_index++] = '\\';
28842660Smarkm                }
28942660Smarkm              printed_line[pl_index] = '\0';
29042660Smarkm            }
29121495Sjmacd
29242660Smarkm          /* We have the exact line as it should appear on the screen.
29342660Smarkm             Check to see if this line matches the one already appearing
29442660Smarkm             on the screen. */
29542660Smarkm          entry = display[line_index + win->first_row];
29621495Sjmacd
29742660Smarkm          /* If the screen line is inversed, then we have to clear
298116525Sru             the line from the screen first.  Why, I don't know.
299116525Sru             (But don't do this if we have no visible entries, as can
300116525Sru             happen if the window is shrunk very small.)  */
301116525Sru          if ((entry && entry->inverse)
302100513Sru	      /* Need to erase the line if it has escape sequences.  */
303100513Sru	      || (raw_escapes_p && strchr (entry->text, '\033') != 0))
30442660Smarkm            {
30542660Smarkm              terminal_goto_xy (0, line_index + win->first_row);
30642660Smarkm              terminal_clear_to_eol ();
30742660Smarkm              entry->inverse = 0;
30842660Smarkm              entry->text[0] = '\0';
30942660Smarkm              entry->textlen = 0;
31042660Smarkm            }
31121495Sjmacd
31242660Smarkm          /* Find the offset where these lines differ. */
31342660Smarkm          for (i = 0; i < pl_index; i++)
31442660Smarkm            if (printed_line[i] != entry->text[i])
31542660Smarkm              break;
31621495Sjmacd
31742660Smarkm          /* If the lines are not the same length, or if they differed
31842660Smarkm             at all, we must do some redrawing. */
31942660Smarkm          if ((i != pl_index) || (pl_index != entry->textlen))
32042660Smarkm            {
32142660Smarkm              /* Move to the proper point on the terminal. */
32242660Smarkm              terminal_goto_xy (i, line_index + win->first_row);
32321495Sjmacd
32442660Smarkm              /* If there is any text to print, print it. */
32542660Smarkm              if (i != pl_index)
32642660Smarkm                terminal_put_text (printed_line + i);
32721495Sjmacd
32842660Smarkm              /* If the printed text didn't extend all the way to the edge
32942660Smarkm                 of the window, and text was appearing between here and the
33042660Smarkm                 edge of the window, clear from here to the end of the line. */
331100513Sru              if ((pl_index < win->width + pl_ignore
332100513Sru		   && pl_index < entry->textlen)
333100513Sru		  || (entry->inverse))
33442660Smarkm                terminal_clear_to_eol ();
33521495Sjmacd
33642660Smarkm              fflush (stdout);
33721495Sjmacd
33842660Smarkm              /* Update the display text buffer. */
339146515Sru	      if (strlen (printed_line) > (unsigned int) screenwidth)
340100513Sru		/* printed_line[] can include more than screenwidth
341100513Sru		   characters if we are under -R and there are escape
342100513Sru		   sequences in it.  However, entry->text was
343100513Sru		   allocated (in display_initialize_display) for
344100513Sru		   screenwidth characters only.  */
345100513Sru		entry->text = xrealloc (entry->text, strlen (printed_line)+1);
34642660Smarkm              strcpy (entry->text + i, printed_line + i);
34742660Smarkm              entry->textlen = pl_index;
34821495Sjmacd
34942660Smarkm              /* Lines showing node text are not in inverse.  Only modelines
35042660Smarkm                 have that distinction. */
35142660Smarkm              entry->inverse = 0;
35242660Smarkm            }
35321495Sjmacd
35442660Smarkm          /* We have done at least one line.  Increment our screen line
35542660Smarkm             index, and check against the bottom of the window. */
35642660Smarkm          if (++line_index == win->height)
35742660Smarkm            break;
35821495Sjmacd
35942660Smarkm          /* A line has been displayed, and the screen reflects that state.
36042660Smarkm             If there is typeahead pending, then let that typeahead be read
36142660Smarkm             now, instead of continuing with the display. */
36242660Smarkm          if (info_any_buffered_input_p ())
36342660Smarkm            {
36442660Smarkm              free (printed_line);
36542660Smarkm              display_was_interrupted_p = 1;
36642660Smarkm              return;
36742660Smarkm            }
36821495Sjmacd
36942660Smarkm          /* Reset PL_INDEX to the start of the line. */
37042660Smarkm          pl_index = 0;
371100513Sru	  pl_ignore = 0;	/* this is computed per line */
37221495Sjmacd
37342660Smarkm          /* If there are characters from REP left to print, stuff them
37442660Smarkm             into the buffer now. */
37542660Smarkm          if (rep_carried_over)
37642660Smarkm            for (; rep[pl_index]; pl_index++)
37742660Smarkm              printed_line[pl_index] = rep[pl_index];
37821495Sjmacd
37942660Smarkm          /* If this window has chosen not to wrap lines, skip to the end
38042660Smarkm             of the physical line in the buffer, and start a new line here. */
38142660Smarkm          if (pl_index && (win->flags & W_NoWrap))
38242660Smarkm            {
38342660Smarkm              char *begin;
38421495Sjmacd
38542660Smarkm              pl_index = 0;
38642660Smarkm              printed_line[0] = '\0';
38721495Sjmacd
38842660Smarkm              begin = nodetext;
389116525Sru
39042660Smarkm              while ((nodetext < last_node_char) && (*nodetext != '\n'))
39142660Smarkm                nodetext++;
39242660Smarkm            }
39342660Smarkm        }
39421495Sjmacd    }
39521495Sjmacd
39621495Sjmacd done_with_node_display:
39721495Sjmacd  /* We have reached the end of the node or the end of the window.  If it
39821495Sjmacd     is the end of the node, then clear the lines of the window from here
39921495Sjmacd     to the end of the window. */
40021495Sjmacd  for (; line_index < win->height; line_index++)
40121495Sjmacd    {
40221495Sjmacd      DISPLAY_LINE *entry = display[line_index + win->first_row];
40321495Sjmacd
40421495Sjmacd      /* If this line has text on it then make it go away. */
40521495Sjmacd      if (entry && entry->textlen)
40642660Smarkm        {
40742660Smarkm          entry->textlen = 0;
40842660Smarkm          entry->text[0] = '\0';
40921495Sjmacd
41042660Smarkm          terminal_goto_xy (0, line_index + win->first_row);
41142660Smarkm          terminal_clear_to_eol ();
41242660Smarkm        }
41321495Sjmacd    }
41421495Sjmacd
41521495Sjmacd  /* Finally, if this window has a modeline it might need to be redisplayed.
41621495Sjmacd     Check the window's modeline against the one in the display, and update
41721495Sjmacd     if necessary. */
41821495Sjmacd  if ((win->flags & W_InhibitMode) == 0)
41921495Sjmacd    {
42021495Sjmacd      window_make_modeline (win);
42121495Sjmacd      line_index = win->first_row + win->height;
42221495Sjmacd
42321495Sjmacd      /* This display line must both be in inverse, and have the same
42442660Smarkm         contents. */
42521495Sjmacd      if ((!display[line_index]->inverse) ||
42642660Smarkm          (strcmp (display[line_index]->text, win->modeline) != 0))
42742660Smarkm        {
42842660Smarkm          terminal_goto_xy (0, line_index);
42942660Smarkm          terminal_begin_inverse ();
43042660Smarkm          terminal_put_text (win->modeline);
43142660Smarkm          terminal_end_inverse ();
43242660Smarkm          strcpy (display[line_index]->text, win->modeline);
43342660Smarkm          display[line_index]->inverse = 1;
43442660Smarkm          display[line_index]->textlen = strlen (win->modeline);
43542660Smarkm          fflush (stdout);
43642660Smarkm        }
43721495Sjmacd    }
43821495Sjmacd
43921495Sjmacd  /* Okay, this window doesn't need updating anymore. */
44021495Sjmacd  win->flags &= ~W_UpdateWindow;
44121495Sjmacd  free (printed_line);
44221495Sjmacd  fflush (stdout);
44321495Sjmacd}
44421495Sjmacd
44521495Sjmacd/* Scroll the region of the_display starting at START, ending at END, and
44621495Sjmacd   moving the lines AMOUNT lines.  If AMOUNT is less than zero, the lines
44721495Sjmacd   are moved up in the screen, otherwise down.  Actually, it is possible
44821495Sjmacd   for no scrolling to take place in the case that the terminal doesn't
44921495Sjmacd   support it.  This doesn't matter to us. */
45021495Sjmacdvoid
451146515Srudisplay_scroll_display (int start, int end, int amount)
45221495Sjmacd{
45321495Sjmacd  register int i, last;
45421495Sjmacd  DISPLAY_LINE *temp;
45521495Sjmacd
45621495Sjmacd  /* If this terminal cannot do scrolling, give up now. */
45721495Sjmacd  if (!terminal_can_scroll)
45821495Sjmacd    return;
45921495Sjmacd
46021495Sjmacd  /* If there isn't anything displayed on the screen because it is too
46121495Sjmacd     small, quit now. */
46221495Sjmacd  if (!the_display[0])
46321495Sjmacd    return;
46421495Sjmacd
46521495Sjmacd  /* If there is typeahead pending, then don't actually do any scrolling. */
46621495Sjmacd  if (info_any_buffered_input_p ())
46721495Sjmacd    return;
46821495Sjmacd
46921495Sjmacd  /* Do it on the screen. */
47021495Sjmacd  terminal_scroll_terminal (start, end, amount);
47121495Sjmacd
47221495Sjmacd  /* Now do it in the display buffer so our contents match the screen. */
47321495Sjmacd  if (amount > 0)
47421495Sjmacd    {
47521495Sjmacd      last = end + amount;
47621495Sjmacd
47721495Sjmacd      /* Shift the lines to scroll right into place. */
47821495Sjmacd      for (i = 0; i < (end - start); i++)
47942660Smarkm        {
48042660Smarkm          temp = the_display[last - i];
48142660Smarkm          the_display[last - i] = the_display[end - i];
48242660Smarkm          the_display[end - i] = temp;
48342660Smarkm        }
48421495Sjmacd
48521495Sjmacd      /* The lines have been shifted down in the buffer.  Clear all of the
48642660Smarkm         lines that were vacated. */
48721495Sjmacd      for (i = start; i != (start + amount); i++)
48842660Smarkm        {
48942660Smarkm          the_display[i]->text[0] = '\0';
49042660Smarkm          the_display[i]->textlen = 0;
49142660Smarkm          the_display[i]->inverse = 0;
49242660Smarkm        }
49321495Sjmacd    }
49421495Sjmacd
49521495Sjmacd  if (amount < 0)
49621495Sjmacd    {
49721495Sjmacd      last = start + amount;
49821495Sjmacd      for (i = 0; i < (end - start); i++)
49942660Smarkm        {
50042660Smarkm          temp = the_display[last + i];
50142660Smarkm          the_display[last + i] = the_display[start + i];
50242660Smarkm          the_display[start + i] = temp;
50342660Smarkm        }
50421495Sjmacd
50521495Sjmacd      /* The lines have been shifted up in the buffer.  Clear all of the
50642660Smarkm         lines that are left over. */
50721495Sjmacd      for (i = end + amount; i != end; i++)
50842660Smarkm        {
50942660Smarkm          the_display[i]->text[0] = '\0';
51042660Smarkm          the_display[i]->textlen = 0;
51142660Smarkm          the_display[i]->inverse = 0;
51242660Smarkm        }
51321495Sjmacd    }
51421495Sjmacd}
51521495Sjmacd
51621495Sjmacd/* Try to scroll lines in WINDOW.  OLD_PAGETOP is the pagetop of WINDOW before
51721495Sjmacd   having had its line starts recalculated.  OLD_STARTS is the list of line
51821495Sjmacd   starts that used to appear in this window.  OLD_COUNT is the number of lines
51921495Sjmacd   that appear in the OLD_STARTS array. */
52021495Sjmacdvoid
521146515Srudisplay_scroll_line_starts (WINDOW *window, int old_pagetop,
522146515Sru    char **old_starts, int old_count)
52321495Sjmacd{
52442660Smarkm  register int i, old, new;     /* Indices into the line starts arrays. */
52542660Smarkm  int last_new, last_old;       /* Index of the last visible line. */
52642660Smarkm  int old_first, new_first;     /* Index of the first changed line. */
52721495Sjmacd  int unchanged_at_top = 0;
52821495Sjmacd  int already_scrolled = 0;
52921495Sjmacd
53021495Sjmacd  /* Locate the first line which was displayed on the old window. */
53121495Sjmacd  old_first = old_pagetop;
53221495Sjmacd  new_first = window->pagetop;
53321495Sjmacd
53421495Sjmacd  /* Find the last line currently visible in this window. */
53521495Sjmacd  last_new = window->pagetop + (window->height - 1);
53621495Sjmacd  if (last_new > window->line_count)
53721495Sjmacd    last_new = window->line_count - 1;
53821495Sjmacd
53921495Sjmacd  /* Find the last line which used to be currently visible in this window. */
54021495Sjmacd  last_old = old_pagetop + (window->height - 1);
54121495Sjmacd  if (last_old > old_count)
54221495Sjmacd    last_old = old_count - 1;
54321495Sjmacd
54421495Sjmacd  for (old = old_first, new = new_first;
54521495Sjmacd       old < last_old && new < last_new;
54621495Sjmacd       old++, new++)
54721495Sjmacd    if (old_starts[old] != window->line_starts[new])
54821495Sjmacd      break;
54921495Sjmacd    else
55021495Sjmacd      unchanged_at_top++;
55121495Sjmacd
55221495Sjmacd  /* Loop through the old lines looking for a match in the new lines. */
55321495Sjmacd  for (old = old_first + unchanged_at_top; old < last_old; old++)
55421495Sjmacd    {
55521495Sjmacd      for (new = new_first; new < last_new; new++)
55642660Smarkm        if (old_starts[old] == window->line_starts[new])
55742660Smarkm          {
55842660Smarkm            /* Find the extent of the matching lines. */
55942660Smarkm            for (i = 0; (old + i) < last_old; i++)
56042660Smarkm              if (old_starts[old + i] != window->line_starts[new + i])
56142660Smarkm                break;
56221495Sjmacd
56342660Smarkm            /* Scroll these lines if there are enough of them. */
56442660Smarkm            {
56542660Smarkm              int start, end, amount;
56621495Sjmacd
56742660Smarkm              start = (window->first_row
56842660Smarkm                       + ((old + already_scrolled) - old_pagetop));
56942660Smarkm              amount = new - (old + already_scrolled);
57042660Smarkm              end = window->first_row + window->height;
57121495Sjmacd
57242660Smarkm              /* If we are shifting the block of lines down, then the last
57342660Smarkm                 AMOUNT lines will become invisible.  Thus, don't bother
57442660Smarkm                 scrolling them. */
57542660Smarkm              if (amount > 0)
57642660Smarkm                end -= amount;
57721495Sjmacd
57842660Smarkm              if ((end - start) > 0)
57942660Smarkm                {
58042660Smarkm                  display_scroll_display (start, end, amount);
58121495Sjmacd
58242660Smarkm                  /* Some lines have been scrolled.  Simulate the scrolling
58342660Smarkm                     by offsetting the value of the old index. */
58442660Smarkm                  old += i;
58542660Smarkm                  already_scrolled += amount;
58642660Smarkm                }
58742660Smarkm            }
58842660Smarkm          }
58921495Sjmacd    }
59021495Sjmacd}
59121495Sjmacd
59221495Sjmacd/* Move the screen cursor to directly over the current character in WINDOW. */
59321495Sjmacdvoid
594146515Srudisplay_cursor_at_point (WINDOW *window)
59521495Sjmacd{
59621495Sjmacd  int vpos, hpos;
59721495Sjmacd
59821495Sjmacd  vpos = window_line_of_point (window) - window->pagetop + window->first_row;
59921495Sjmacd  hpos = window_get_cursor_column (window);
60021495Sjmacd  terminal_goto_xy (hpos, vpos);
60142660Smarkm  fflush (stdout);
60221495Sjmacd}
60321495Sjmacd
60421495Sjmacd/* **************************************************************** */
60542660Smarkm/*                                                                  */
60642660Smarkm/*                   Functions Static to this File                  */
60742660Smarkm/*                                                                  */
60821495Sjmacd/* **************************************************************** */
60921495Sjmacd
61021495Sjmacd/* Make a DISPLAY_LINE ** with width and height. */
61121495Sjmacdstatic DISPLAY_LINE **
612146515Srumake_display (int width, int height)
61321495Sjmacd{
61421495Sjmacd  register int i;
61521495Sjmacd  DISPLAY_LINE **display;
61621495Sjmacd
61721495Sjmacd  display = (DISPLAY_LINE **)xmalloc ((1 + height) * sizeof (DISPLAY_LINE *));
61821495Sjmacd
61921495Sjmacd  for (i = 0; i < height; i++)
62021495Sjmacd    {
62121495Sjmacd      display[i] = (DISPLAY_LINE *)xmalloc (sizeof (DISPLAY_LINE));
62221495Sjmacd      display[i]->text = (char *)xmalloc (1 + width);
62321495Sjmacd      display[i]->textlen = 0;
62421495Sjmacd      display[i]->inverse = 0;
62521495Sjmacd    }
62621495Sjmacd  display[i] = (DISPLAY_LINE *)NULL;
62721495Sjmacd  return (display);
62821495Sjmacd}
62921495Sjmacd
63021495Sjmacd/* Free the storage allocated to DISPLAY. */
63121495Sjmacdstatic void
632146515Srufree_display (DISPLAY_LINE **display)
63321495Sjmacd{
63421495Sjmacd  register int i;
63521495Sjmacd  register DISPLAY_LINE *display_line;
63621495Sjmacd
63721495Sjmacd  if (!display)
63821495Sjmacd    return;
63921495Sjmacd
64042660Smarkm  for (i = 0; (display_line = display[i]); i++)
64121495Sjmacd    {
64221495Sjmacd      free (display_line->text);
64321495Sjmacd      free (display_line);
64421495Sjmacd    }
64521495Sjmacd  free (display);
64621495Sjmacd}
647