display.c revision 1.1 1 1.1 christos /* $NetBSD: display.c,v 1.1 2016/01/14 00:11:29 christos 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.1 christos if (isprint (*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