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