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