(comint-read-input-ring): Make regexp stricter.
[bpt/emacs.git] / src / xdisp.c
CommitLineData
a2889657 1/* Display generation from window structure and buffer text.
76412d64 2 Copyright (C) 1985, 86, 87, 88, 93, 94 Free Software Foundation, Inc.
a2889657
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
b1d1124b 8the Free Software Foundation; either version 2, or (at your option)
a2889657
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
18160b98 21#include <config.h>
a2889657
JB
22#include <stdio.h>
23/*#include <ctype.h>*/
24#undef NULL
25#include "lisp.h"
44fa5b1e 26#include "frame.h"
a2889657
JB
27#include "window.h"
28#include "termchar.h"
29#include "dispextern.h"
30#include "buffer.h"
31#include "indent.h"
32#include "commands.h"
33#include "macros.h"
34#include "disptab.h"
30c566e4 35#include "termhooks.h"
b0a0fbda 36#include "intervals.h"
a2889657 37
76412d64
RS
38#ifdef USE_X_TOOLKIT
39extern void set_frame_menubar ();
40#endif
41
a2889657
JB
42extern int interrupt_input;
43extern int command_loop_level;
44
45/* Nonzero means print newline before next minibuffer message. */
46
47int noninteractive_need_newline;
48
49#define min(a, b) ((a) < (b) ? (a) : (b))
50#define max(a, b) ((a) > (b) ? (a) : (b))
51
52/* The buffer position of the first character appearing
44fa5b1e
JB
53 entirely or partially on the current frame line.
54 Or zero, which disables the optimization for the current frame line. */
a2889657
JB
55static int this_line_bufpos;
56
57/* Number of characters past the end of this line,
58 including the terminating newline */
59static int this_line_endpos;
60
44fa5b1e 61/* The vertical position of this frame line. */
a2889657
JB
62static int this_line_vpos;
63
44fa5b1e 64/* Hpos value for start of display on this frame line.
a2889657
JB
65 Usually zero, but negative if first character really began
66 on previous line */
67static int this_line_start_hpos;
68
69/* Buffer that this_line variables are describing. */
70static struct buffer *this_line_buffer;
71
72/* Set by try_window_id to the vpos of first of any lines
44fa5b1e 73 scrolled on to the bottom of the frame. These lines should
a2889657
JB
74 not be included in any general scroll computation. */
75static int scroll_bottom_vpos;
76
77/* Value of echo_area_glyphs when it was last acted on.
44fa5b1e 78 If this is nonzero, there is a message on the frame
a2889657
JB
79 in the minibuffer and it should be erased as soon
80 as it is no longer requested to appear. */
81char *previous_echo_glyphs;
82
44fa5b1e 83/* Nonzero means truncate lines in all windows less wide than the frame */
a2889657
JB
84int truncate_partial_width_windows;
85
86Lisp_Object Vglobal_mode_string;
87
88/* Marker for where to display an arrow on top of the buffer text. */
89Lisp_Object Voverlay_arrow_position;
90
91/* String to display for the arrow. */
92Lisp_Object Voverlay_arrow_string;
93
94/* Values of those variables at last redisplay. */
ded34426 95static Lisp_Object last_arrow_position, last_arrow_string;
a2889657 96
cf074754
RS
97Lisp_Object Qmenu_bar_update_hook;
98
a2889657
JB
99/* Nonzero if overlay arrow has been displayed once in this window. */
100static int overlay_arrow_seen;
101
fba9ce76
RS
102/* Nonzero means highlight the region even in nonselected windows. */
103static int highlight_nonselected_windows;
104
44fa5b1e 105/* If cursor motion alone moves point off frame,
a2889657
JB
106 Try scrolling this many lines up or down if that will bring it back. */
107int scroll_step;
108
109/* Nonzero if try_window_id has made blank lines at window bottom
110 since the last redisplay that paused */
111static int blank_end_of_window;
112
113/* Number of windows showing the buffer of the selected window.
114 keyboard.c refers to this. */
115int buffer_shared;
116
44fa5b1e 117/* display_text_line sets these to the frame position (origin 0) of point,
a2889657
JB
118 whether the window is selected or not.
119 Set one to -1 first to determine whether point was found afterwards. */
120
121static int cursor_vpos;
122static int cursor_hpos;
123
124int debug_end_pos;
125
126/* Nonzero means display mode line highlighted */
127int mode_line_inverse_video;
128
129static void echo_area_display ();
130void mark_window_display_accurate ();
131static void redisplay_windows ();
132static void redisplay_window ();
90adcf20
RS
133static void update_menu_bars ();
134static void update_menu_bar ();
a2889657
JB
135static void try_window ();
136static int try_window_id ();
137static struct position *display_text_line ();
138static void display_mode_line ();
139static int display_mode_element ();
140static char *fmodetrunc ();
141static char *decode_mode_spec ();
142static int display_string ();
7ce2c095 143static void display_menu_bar ();
aa6d10fa 144static int display_count_lines ();
a2889657
JB
145
146/* Prompt to display in front of the minibuffer contents */
147char *minibuf_prompt;
148
149/* Width in columns of current minibuffer prompt. */
150int minibuf_prompt_width;
151
152/* Message to display instead of minibuffer contents
153 This is what the functions error and message make,
154 and command echoing uses it as well.
155 It overrides the minibuf_prompt as well as the buffer. */
156char *echo_area_glyphs;
157
90adcf20
RS
158/* This is the length of the message in echo_area_glyphs. */
159int echo_area_glyphs_length;
160
a2889657
JB
161/* true iff we should redraw the mode lines on the next redisplay */
162int update_mode_lines;
163
164/* Smallest number of characters before the gap
165 at any time since last redisplay that finished.
166 Valid for current buffer when try_window_id can be called. */
167int beg_unchanged;
168
169/* Smallest number of characters after the gap
170 at any time since last redisplay that finished.
171 Valid for current buffer when try_window_id can be called. */
172int end_unchanged;
173
174/* MODIFF as of last redisplay that finished;
175 if it matches MODIFF, beg_unchanged and end_unchanged
176 contain no useful information */
177int unchanged_modified;
178
179/* Nonzero if head_clip or tail_clip of current buffer has changed
180 since last redisplay that finished */
181int clip_changed;
182
183/* Nonzero if window sizes or contents have changed
184 since last redisplay that finished */
185int windows_or_buffers_changed;
186
aa6d10fa
RS
187/* Nonzero after display_mode_line if %l was used
188 and it displayed a line number. */
189int line_number_displayed;
190
191/* Maximum buffer size for which to display line numbers. */
192int line_number_display_limit;
a2889657 193\f
90adcf20 194/* Display an echo area message M with a specified length of LEN chars.
48ae5f0a
KH
195 The string may include null characters. If m is 0, clear out any
196 existing message, and let the minibuffer text show through.
197 Do not pass text that is stored in a Lisp string. */
90adcf20
RS
198
199void
200message2 (m, len)
201 char *m;
202 int len;
203{
204 if (noninteractive)
205 {
206 if (noninteractive_need_newline)
207 putc ('\n', stderr);
208 noninteractive_need_newline = 0;
209 fwrite (m, len, 1, stderr);
210 if (cursor_in_echo_area == 0)
211 fprintf (stderr, "\n");
212 fflush (stderr);
213 }
214 /* A null message buffer means that the frame hasn't really been
215 initialized yet. Error messages get reported properly by
216 cmd_error, so this must be just an informative message; toss it. */
217 else if (INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame))
218 {
219#ifdef MULTI_FRAME
220 Lisp_Object minibuf_frame;
221
222 choose_minibuf_frame ();
223 minibuf_frame = WINDOW_FRAME (XWINDOW (minibuf_window));
224 FRAME_SAMPLE_VISIBILITY (XFRAME (minibuf_frame));
225 if (FRAME_VISIBLE_P (selected_frame)
226 && ! FRAME_VISIBLE_P (XFRAME (minibuf_frame)))
227 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (minibuf_window)));
228#endif
229
230 if (m)
231 {
232 echo_area_glyphs = m;
233 echo_area_glyphs_length = len;
234 }
ded34426
JB
235 else
236 echo_area_glyphs = previous_echo_glyphs = 0;
237
238 do_pending_window_change ();
239 echo_area_display ();
240 update_frame (XFRAME (XWINDOW (minibuf_window)->frame), 1, 1);
241 do_pending_window_change ();
853cf346
RS
242 if (frame_up_to_date_hook != 0 && ! gc_in_progress)
243 (*frame_up_to_date_hook) (XFRAME (XWINDOW (minibuf_window)->frame));
ded34426
JB
244 }
245}
246
48ae5f0a
KH
247void
248message1 (m)
249 char *m;
250{
251 message2 (m, (m ? strlen (m) : 0));
252}
253
76412d64
RS
254/* Truncate what will be displayed in the echo area
255 the next time we display it--but don't redisplay it now. */
256
257void
258truncate_echo_area (len)
259 int len;
260{
261 /* A null message buffer means that the frame hasn't really been
262 initialized yet. Error messages get reported properly by
263 cmd_error, so this must be just an informative message; toss it. */
264 if (!noninteractive && INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame))
265 echo_area_glyphs_length = len;
266}
267
44fa5b1e 268/* Nonzero if FRAME_MESSAGE_BUF (selected_frame) is being used by print;
9c74a0dd
JB
269 zero if being used by message. */
270int message_buf_print;
271
81d478f3
JB
272/* Dump an informative message to the minibuf. If m is 0, clear out
273 any existing message, and let the minibuffer text show through. */
a2889657 274/* VARARGS 1 */
a2889657
JB
275void
276message (m, a1, a2, a3)
277 char *m;
278{
279 if (noninteractive)
280 {
81d478f3
JB
281 if (m)
282 {
283 if (noninteractive_need_newline)
284 putc ('\n', stderr);
285 noninteractive_need_newline = 0;
286 fprintf (stderr, m, a1, a2, a3);
c4f14ccb
RS
287 if (cursor_in_echo_area == 0)
288 fprintf (stderr, "\n");
81d478f3
JB
289 fflush (stderr);
290 }
a2889657 291 }
1f40cad2 292 else if (INTERACTIVE)
a2889657 293 {
1f40cad2
JB
294 /* The frame whose minibuffer we're going to display the message on.
295 It may be larger than the selected frame, so we need
296 to use its buffer, not the selected frame's buffer. */
297 FRAME_PTR echo_frame;
298#ifdef MULTI_FRAME
299 choose_minibuf_frame ();
300 echo_frame = XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
301#else
302 echo_frame = selected_frame;
303#endif
304
305 /* A null message buffer means that the frame hasn't really been
306 initialized yet. Error messages get reported properly by
307 cmd_error, so this must be just an informative message; toss it. */
308 if (FRAME_MESSAGE_BUF (echo_frame))
81d478f3 309 {
1f40cad2
JB
310 if (m)
311 {
90adcf20 312 int len;
a2889657 313#ifdef NO_ARG_ARRAY
90adcf20
RS
314 int a[3];
315 a[0] = a1;
316 a[1] = a2;
317 a[2] = a3;
a2889657 318
90adcf20
RS
319 len = doprnt (FRAME_MESSAGE_BUF (echo_frame),
320 FRAME_WIDTH (echo_frame), m, 0, 3, a);
a2889657 321#else
90adcf20
RS
322 len = doprnt (FRAME_MESSAGE_BUF (echo_frame),
323 FRAME_WIDTH (echo_frame), m, 0, 3, &a1);
1f40cad2 324#endif /* NO_ARG_ARRAY */
1f40cad2 325
90adcf20 326 message2 (FRAME_MESSAGE_BUF (echo_frame), len);
1f40cad2
JB
327 }
328 else
329 message1 (0);
330
331 /* Print should start at the beginning of the message
332 buffer next time. */
333 message_buf_print = 0;
81d478f3 334 }
a2889657
JB
335 }
336}
337
338static void
339echo_area_display ()
340{
341 register int vpos;
44fa5b1e 342 FRAME_PTR f;
a2889657 343
44fa5b1e
JB
344#ifdef MULTI_FRAME
345 choose_minibuf_frame ();
b1d1124b
JB
346#endif
347
44fa5b1e 348 f = XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
a2889657 349
44fa5b1e 350 if (! FRAME_VISIBLE_P (f))
a2889657 351 return;
a2889657 352
44fa5b1e 353 if (frame_garbaged)
a2889657 354 {
02a9b6e4 355 redraw_garbaged_frames ();
44fa5b1e 356 frame_garbaged = 0;
a2889657
JB
357 }
358
359 if (echo_area_glyphs || minibuf_level == 0)
360 {
361 vpos = XFASTINT (XWINDOW (minibuf_window)->top);
44fa5b1e 362 get_display_line (f, vpos, 0);
a2889657
JB
363 display_string (XWINDOW (minibuf_window), vpos,
364 echo_area_glyphs ? echo_area_glyphs : "",
90adcf20 365 echo_area_glyphs ? echo_area_glyphs_length : -1,
278feba9 366 0, 0, 0, 0, FRAME_WIDTH (f));
a2889657
JB
367
368 /* If desired cursor location is on this line, put it at end of text */
44fa5b1e
JB
369 if (FRAME_CURSOR_Y (f) == vpos)
370 FRAME_CURSOR_X (f) = FRAME_DESIRED_GLYPHS (f)->used[vpos];
daa37602
JB
371
372 /* Fill the rest of the minibuffer window with blank lines. */
373 {
374 int i;
375
b2a76982
RS
376 for (i = vpos + 1;
377 i < vpos + XFASTINT (XWINDOW (minibuf_window)->height); i++)
daa37602 378 {
44fa5b1e 379 get_display_line (f, i, 0);
daa37602 380 display_string (XWINDOW (minibuf_window), vpos,
278feba9 381 "", 0, 0, 0, 0, 0, FRAME_WIDTH (f));
daa37602
JB
382 }
383 }
a2889657
JB
384 }
385 else if (!EQ (minibuf_window, selected_window))
386 windows_or_buffers_changed++;
387
388 if (EQ (minibuf_window, selected_window))
389 this_line_bufpos = 0;
390
391 previous_echo_glyphs = echo_area_glyphs;
392}
96a410bc
KH
393
394#ifdef HAVE_X_WINDOWS
395/* I'm trying this out because I saw Unimpress use it, but it's
396 possible that this may mess adversely with some window managers. -jla
397
398 Wouldn't it be nice to use something like mode-line-format to
399 describe frame titles? -JimB */
400
401/* Change the title of the frame to the name of the buffer displayed
402 in the currently selected window. Don't do this for minibuffer frames,
403 and don't do it when there's only one non-minibuffer frame. */
404static void
405x_consider_frame_title (frame)
406 Lisp_Object frame;
407{
408 FRAME_PTR f = XFRAME (frame);
409
410 if (FRAME_X_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
411 {
0b67772d 412 Lisp_Object title;
96a410bc 413
0b67772d 414 title = Qnil;
96a410bc
KH
415 if (! EQ (Fnext_frame (frame, Qnil), frame))
416 title = XBUFFER (XWINDOW (f->selected_window)->buffer)->name;
417
418 x_implicitly_set_name (f, title, Qnil);
419 }
420}
421#endif
a2889657 422\f
90adcf20
RS
423/* Prepare for redisplay by updating menu-bar item lists when appropriate.
424 This can't be done in `redisplay' itself because it can call eval. */
425
426void
427prepare_menu_bars ()
428{
429 register struct window *w = XWINDOW (selected_window);
430 int all_windows;
431
432 if (noninteractive)
433 return;
434
435 /* Set the visible flags for all frames.
436 Do this before checking for resized or garbaged frames; they want
437 to know if their frames are visible.
438 See the comment in frame.h for FRAME_SAMPLE_VISIBILITY. */
439 {
440 Lisp_Object tail, frame;
441
442 FOR_EACH_FRAME (tail, frame)
443 FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
444 }
445
446 /* Notice any pending interrupt request to change frame size. */
447 do_pending_window_change ();
448
449 if (frame_garbaged)
450 {
451 redraw_garbaged_frames ();
452 frame_garbaged = 0;
453 }
454
ecf7de9b
RS
455 all_windows = (update_mode_lines || buffer_shared > 1
456 || clip_changed || windows_or_buffers_changed);
90adcf20
RS
457
458 /* Update the menu bar item lists, if appropriate.
459 This has to be done before any actual redisplay
460 or generation of display lines. */
461 if (all_windows)
462 {
463 Lisp_Object tail, frame;
464
465 FOR_EACH_FRAME (tail, frame)
ecf7de9b 466 update_menu_bar (XFRAME (frame));
90adcf20 467 }
ecf7de9b
RS
468 else
469 update_menu_bar (selected_frame);
90adcf20
RS
470}
471\f
44fa5b1e 472/* Do a frame update, taking possible shortcuts into account.
a2889657
JB
473 This is the main external entry point for redisplay.
474
475 If the last redisplay displayed an echo area message and that
476 message is no longer requested, we clear the echo area
477 or bring back the minibuffer if that is in use.
478
90adcf20
RS
479 Do not call eval from within this function.
480 Calls to eval after the call to echo_area_display would confuse
481 the display_line mechanism and would cause a crash.
482 Calls to eval before that point will work most of the time,
483 but can still lose, because this function
484 can be called from signal handlers; with alarms set up;
a2889657 485 or with synchronous processes running.
90adcf20 486
a2889657
JB
487 See Fcall_process; if you called it from here, it could be
488 entered recursively. */
489
0d231165
RS
490static int do_verify_charstarts;
491
a2889657
JB
492void
493redisplay ()
494{
495 register struct window *w = XWINDOW (selected_window);
496 register int pause;
497 int must_finish = 0;
498 int all_windows;
499 register int tlbufpos, tlendpos;
500 struct position pos;
501 extern int input_pending;
502
503 if (noninteractive)
504 return;
505
d724d989
JB
506 /* Set the visible flags for all frames.
507 Do this before checking for resized or garbaged frames; they want
508 to know if their frames are visible.
509 See the comment in frame.h for FRAME_SAMPLE_VISIBILITY. */
510 {
35f56f96 511 Lisp_Object tail, frame;
d724d989 512
35f56f96
JB
513 FOR_EACH_FRAME (tail, frame)
514 FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
d724d989
JB
515 }
516
44fa5b1e 517 /* Notice any pending interrupt request to change frame size. */
a2889657
JB
518 do_pending_window_change ();
519
44fa5b1e 520 if (frame_garbaged)
a2889657 521 {
02a9b6e4 522 redraw_garbaged_frames ();
44fa5b1e 523 frame_garbaged = 0;
a2889657
JB
524 }
525
a2889657
JB
526 if (clip_changed || windows_or_buffers_changed)
527 update_mode_lines++;
528
529 /* Detect case that we need to write a star in the mode line. */
530 if (XFASTINT (w->last_modified) < MODIFF
531 && XFASTINT (w->last_modified) <= current_buffer->save_modified)
532 {
533 w->update_mode_line = Qt;
534 if (buffer_shared > 1)
535 update_mode_lines++;
536 }
537
44fa5b1e 538 FRAME_SCROLL_BOTTOM_VPOS (XFRAME (w->frame)) = -1;
a2889657
JB
539
540 all_windows = update_mode_lines || buffer_shared > 1;
a2889657
JB
541
542 /* If specs for an arrow have changed, do thorough redisplay
543 to ensure we remove any arrow that should no longer exist. */
ded34426
JB
544 if (! EQ (Voverlay_arrow_position, last_arrow_position)
545 || ! EQ (Voverlay_arrow_string, last_arrow_string))
a2889657
JB
546 all_windows = 1, clip_changed = 1;
547
90adcf20
RS
548 /* Normally the message* functions will have already displayed and
549 updated the echo area, but the frame may have been trashed, or
550 the update may have been preempted, so display the echo area
551 again here. */
552 if (echo_area_glyphs || previous_echo_glyphs)
553 {
554 echo_area_display ();
555 must_finish = 1;
556 }
557
bd66d1ba
RS
558 /* If showing region, and mark has changed, must redisplay whole window. */
559 if (((!NILP (Vtransient_mark_mode)
560 && !NILP (XBUFFER (w->buffer)->mark_active))
561 != !NILP (w->region_showing))
82d04750
JB
562 || (!NILP (w->region_showing)
563 && !EQ (w->region_showing,
564 Fmarker_position (XBUFFER (w->buffer)->mark))))
bd66d1ba
RS
565 this_line_bufpos = -1;
566
a2889657
JB
567 tlbufpos = this_line_bufpos;
568 tlendpos = this_line_endpos;
265a9e55 569 if (!all_windows && tlbufpos > 0 && NILP (w->update_mode_line)
44fa5b1e 570 && FRAME_VISIBLE_P (XFRAME (w->frame))
a2889657
JB
571 /* Make sure recorded data applies to current buffer, etc */
572 && this_line_buffer == current_buffer
573 && current_buffer == XBUFFER (w->buffer)
265a9e55 574 && NILP (w->force_start)
a2889657 575 /* Point must be on the line that we have info recorded about */
ae3b1442
KH
576 && PT >= tlbufpos
577 && PT <= Z - tlendpos
a2889657
JB
578 /* All text outside that line, including its final newline,
579 must be unchanged */
580 && (XFASTINT (w->last_modified) >= MODIFF
581 || (beg_unchanged >= tlbufpos - 1
582 && GPT >= tlbufpos
05ba02eb
JB
583 /* If selective display, can't optimize
584 if the changes start at the beginning of the line. */
585 && ((XTYPE (current_buffer->selective_display) == Lisp_Int
586 && XINT (current_buffer->selective_display) > 0
587 ? (beg_unchanged >= tlbufpos
588 && GPT > tlbufpos)
589 : 1))
a2889657
JB
590 && end_unchanged >= tlendpos
591 && Z - GPT >= tlendpos)))
592 {
593 if (tlbufpos > BEGV && FETCH_CHAR (tlbufpos - 1) != '\n'
594 && (tlbufpos == ZV
595 || FETCH_CHAR (tlbufpos) == '\n'))
596 /* Former continuation line has disappeared by becoming empty */
597 goto cancel;
598 else if (XFASTINT (w->last_modified) < MODIFF
599 || MINI_WINDOW_P (w))
600 {
601 cursor_vpos = -1;
602 overlay_arrow_seen = 0;
603 display_text_line (w, tlbufpos, this_line_vpos, this_line_start_hpos,
604 pos_tab_offset (w, tlbufpos));
605 /* If line contains point, is not continued,
606 and ends at same distance from eob as before, we win */
607 if (cursor_vpos >= 0 && this_line_bufpos
608 && this_line_endpos == tlendpos)
609 {
0d231165
RS
610 /* If this is not the window's last line,
611 we must adjust the charstarts of the lines below. */
612 if (this_line_vpos + 1
613 < XFASTINT (w->top) + window_internal_height (w))
85bcef6c
RS
614 {
615 int left = XFASTINT (w->left);
616 int *charstart_next_line
617 = FRAME_CURRENT_GLYPHS (XFRAME (WINDOW_FRAME (w)))->charstarts[this_line_vpos + 1];
618 int i;
619 int adjust;
620
621 if (Z - tlendpos == ZV)
622 /* This line ends at end of (accessible part of) buffer.
623 There is no newline to count. */
624 adjust = Z - tlendpos - charstart_next_line[left];
625 else
626 /* This line ends in a newline.
627 Must take account of the newline and the rest of the
628 text that follows. */
629 adjust = Z - tlendpos + 1 - charstart_next_line[left];
630
631 adjust_window_charstarts (w, this_line_vpos, adjust);
632 }
46db8486 633
44fa5b1e 634 if (XFASTINT (w->width) != FRAME_WIDTH (XFRAME (WINDOW_FRAME (w))))
a2889657
JB
635 preserve_other_columns (w);
636 goto update;
637 }
638 else
639 goto cancel;
640 }
ae3b1442 641 else if (PT == XFASTINT (w->last_point))
a2889657
JB
642 {
643 if (!must_finish)
644 {
645 do_pending_window_change ();
646 return;
647 }
648 goto update;
649 }
bd66d1ba
RS
650 /* If highlighting the region, we can't just move the cursor. */
651 else if (! (!NILP (Vtransient_mark_mode)
652 && !NILP (current_buffer->mark_active))
653 && NILP (w->region_showing))
a2889657
JB
654 {
655 pos = *compute_motion (tlbufpos, 0,
656 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
ae3b1442 657 PT, 2, - (1 << (SHORTBITS - 1)),
b1d1124b 658 window_internal_width (w) - 1,
de3e8b15 659 XINT (w->hscroll),
e37f06d7 660 pos_tab_offset (w, tlbufpos), w);
a2889657
JB
661 if (pos.vpos < 1)
662 {
44fa5b1e 663 FRAME_CURSOR_X (selected_frame)
a2889657 664 = XFASTINT (w->left) + max (pos.hpos, 0);
44fa5b1e 665 FRAME_CURSOR_Y (selected_frame) = this_line_vpos;
a2889657
JB
666 goto update;
667 }
668 else
669 goto cancel;
670 }
671 cancel:
672 /* Text changed drastically or point moved off of line */
44fa5b1e 673 cancel_line (this_line_vpos, selected_frame);
a2889657
JB
674 }
675
676 this_line_bufpos = 0;
677 all_windows |= buffer_shared > 1;
678
679 if (all_windows)
680 {
35f56f96 681 Lisp_Object tail, frame;
a2889657 682
31b24551
JB
683#ifdef HAVE_X_WINDOWS
684 /* Since we're doing a thorough redisplay, we might as well
685 recompute all our display faces. */
686 clear_face_vector ();
687#endif
688
a2889657 689 /* Recompute # windows showing selected buffer.
8de2d90b 690 This will be incremented each time such a window is displayed. */
a2889657
JB
691 buffer_shared = 0;
692
35f56f96 693 FOR_EACH_FRAME (tail, frame)
30c566e4 694 {
35f56f96
JB
695 FRAME_PTR f = XFRAME (frame);
696
88f22aff 697 /* Mark all the scroll bars to be removed; we'll redeem the ones
30c566e4 698 we want when we redisplay their windows. */
88f22aff
JB
699 if (condemn_scroll_bars_hook)
700 (*condemn_scroll_bars_hook) (f);
30c566e4
JB
701
702 if (FRAME_VISIBLE_P (f))
703 redisplay_windows (FRAME_ROOT_WINDOW (f));
96a410bc 704#ifdef HAVE_X_WINDOWS
98bc00f0
KH
705 else if (FRAME_ICONIFIED_P (f)
706 && ! MINI_WINDOW_P (XWINDOW (f->selected_window)))
96a410bc
KH
707 x_consider_frame_title (frame);
708#endif
30c566e4 709
88f22aff 710 /* Any scroll bars which redisplay_windows should have nuked
30c566e4 711 should now go away. */
88f22aff
JB
712 if (judge_scroll_bars_hook)
713 (*judge_scroll_bars_hook) (f);
30c566e4 714 }
a2889657 715 }
44fa5b1e 716 else if (FRAME_VISIBLE_P (selected_frame))
a2889657
JB
717 {
718 redisplay_window (selected_window, 1);
44fa5b1e 719 if (XFASTINT (w->width) != FRAME_WIDTH (selected_frame))
a2889657
JB
720 preserve_other_columns (w);
721 }
722
723update:
724 /* Prevent various kinds of signals during display update.
725 stdio is not robust about handling signals,
726 which can cause an apparent I/O error. */
727 if (interrupt_input)
728 unrequest_sigio ();
729 stop_polling ();
730
44fa5b1e 731#ifdef MULTI_FRAME
a2889657
JB
732 if (all_windows)
733 {
734 Lisp_Object tail;
735
736 pause = 0;
737
44fa5b1e 738 for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
a2889657 739 {
44fa5b1e 740 FRAME_PTR f;
a2889657 741
44fa5b1e 742 if (XTYPE (XCONS (tail)->car) != Lisp_Frame)
a2889657
JB
743 continue;
744
44fa5b1e 745 f = XFRAME (XCONS (tail)->car);
30c566e4 746 if (FRAME_VISIBLE_P (f))
a2889657 747 {
44fa5b1e 748 pause |= update_frame (f, 0, 0);
a2889657 749 if (!pause)
efc63ef0
RS
750 {
751 mark_window_display_accurate (f->root_window, 1);
752 if (frame_up_to_date_hook != 0)
753 (*frame_up_to_date_hook) (f);
754 }
a2889657
JB
755 }
756 }
757 }
758 else
44fa5b1e 759#endif /* MULTI_FRAME */
6e8290aa 760 {
44fa5b1e
JB
761 if (FRAME_VISIBLE_P (selected_frame))
762 pause = update_frame (selected_frame, 0, 0);
d724d989 763
8de2d90b 764 /* We may have called echo_area_display at the top of this
44fa5b1e
JB
765 function. If the echo area is on another frame, that may
766 have put text on a frame other than the selected one, so the
767 above call to update_frame would not have caught it. Catch
8de2d90b
JB
768 it here. */
769 {
efc63ef0
RS
770 FRAME_PTR mini_frame
771 = XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
8de2d90b 772
44fa5b1e
JB
773 if (mini_frame != selected_frame)
774 pause |= update_frame (mini_frame, 0, 0);
8de2d90b 775 }
6e8290aa 776 }
a2889657 777
44fa5b1e 778 /* If frame does not match, prevent doing single-line-update next time.
a2889657
JB
779 Also, don't forget to check every line to update the arrow. */
780 if (pause)
781 {
782 this_line_bufpos = 0;
265a9e55 783 if (!NILP (last_arrow_position))
a2889657
JB
784 {
785 last_arrow_position = Qt;
786 last_arrow_string = Qt;
787 }
44fa5b1e 788 /* If we pause after scrolling, some lines in current_frame
a2889657
JB
789 may be null, so preserve_other_columns won't be able to
790 preserve all the vertical-bar separators. So, avoid using it
791 in that case. */
44fa5b1e 792 if (XFASTINT (w->width) != FRAME_WIDTH (selected_frame))
a2889657
JB
793 update_mode_lines = 1;
794 }
795
44fa5b1e 796 /* Now text on frame agrees with windows, so
a2889657
JB
797 put info into the windows for partial redisplay to follow */
798
799 if (!pause)
800 {
801 register struct buffer *b = XBUFFER (w->buffer);
802
803 blank_end_of_window = 0;
804 clip_changed = 0;
805 unchanged_modified = BUF_MODIFF (b);
806 beg_unchanged = BUF_GPT (b) - BUF_BEG (b);
807 end_unchanged = BUF_Z (b) - BUF_GPT (b);
808
809 XFASTINT (w->last_point) = BUF_PT (b);
44fa5b1e
JB
810 XFASTINT (w->last_point_x) = FRAME_CURSOR_X (selected_frame);
811 XFASTINT (w->last_point_y) = FRAME_CURSOR_Y (selected_frame);
a2889657
JB
812
813 if (all_windows)
11e82b76 814 mark_window_display_accurate (FRAME_ROOT_WINDOW (selected_frame), 1);
a2889657
JB
815 else
816 {
817 w->update_mode_line = Qnil;
818 XFASTINT (w->last_modified) = BUF_MODIFF (b);
d2f84654 819 w->window_end_valid = w->buffer;
a2889657
JB
820 last_arrow_position = Voverlay_arrow_position;
821 last_arrow_string = Voverlay_arrow_string;
0d231165
RS
822 if (do_verify_charstarts)
823 verify_charstarts (w);
efc63ef0
RS
824 if (frame_up_to_date_hook != 0)
825 (*frame_up_to_date_hook) (selected_frame);
a2889657
JB
826 }
827 update_mode_lines = 0;
828 windows_or_buffers_changed = 0;
829 }
830
831 /* Start SIGIO interrupts coming again.
832 Having them off during the code above
833 makes it less likely one will discard output,
834 but not impossible, since there might be stuff
835 in the system buffer here.
836 But it is much hairier to try to do anything about that. */
837
838 if (interrupt_input)
839 request_sigio ();
840 start_polling ();
841
44fa5b1e 842 /* Change frame size now if a change is pending. */
a2889657 843 do_pending_window_change ();
d8e242fd
RS
844
845 /* If we just did a pending size change, redisplay again
846 for the new size. */
847 if (windows_or_buffers_changed)
848 redisplay ();
a2889657
JB
849}
850
851/* Redisplay, but leave alone any recent echo area message
852 unless another message has been requested in its place.
853
854 This is useful in situations where you need to redisplay but no
855 user action has occurred, making it inappropriate for the message
856 area to be cleared. See tracking_off and
857 wait_reading_process_input for examples of these situations. */
858
859redisplay_preserve_echo_area ()
860{
861 if (echo_area_glyphs == 0 && previous_echo_glyphs != 0)
862 {
863 echo_area_glyphs = previous_echo_glyphs;
864 redisplay ();
865 echo_area_glyphs = 0;
866 }
867 else
868 redisplay ();
869}
870
871void
872mark_window_display_accurate (window, flag)
873 Lisp_Object window;
874 int flag;
875{
876 register struct window *w;
877
265a9e55 878 for (;!NILP (window); window = w->next)
a2889657 879 {
ded34426 880 if (XTYPE (window) != Lisp_Window) abort ();
a2889657
JB
881 w = XWINDOW (window);
882
265a9e55 883 if (!NILP (w->buffer))
bd66d1ba
RS
884 {
885 XFASTINT (w->last_modified)
886 = !flag ? 0
887 : XBUFFER (w->buffer) == current_buffer
888 ? MODIFF : BUF_MODIFF (XBUFFER (w->buffer));
889
890 /* Record if we are showing a region, so can make sure to
891 update it fully at next redisplay. */
892 w->region_showing = (!NILP (Vtransient_mark_mode)
893 && !NILP (XBUFFER (w->buffer)->mark_active)
894 ? Fmarker_position (XBUFFER (w->buffer)->mark)
895 : Qnil);
896 }
897
d2f84654 898 w->window_end_valid = w->buffer;
a2889657
JB
899 w->update_mode_line = Qnil;
900
265a9e55 901 if (!NILP (w->vchild))
a2889657 902 mark_window_display_accurate (w->vchild, flag);
265a9e55 903 if (!NILP (w->hchild))
a2889657
JB
904 mark_window_display_accurate (w->hchild, flag);
905 }
906
907 if (flag)
908 {
909 last_arrow_position = Voverlay_arrow_position;
910 last_arrow_string = Voverlay_arrow_string;
911 }
912 else
913 {
914 /* t is unequal to any useful value of Voverlay_arrow_... */
915 last_arrow_position = Qt;
916 last_arrow_string = Qt;
917 }
918}
919\f
ecf7de9b 920/* Update the menu bar item list for frame F.
90adcf20
RS
921 This has to be done before we start to fill in any display lines,
922 because it can call eval. */
923
924static void
ecf7de9b
RS
925update_menu_bar (f)
926 FRAME_PTR f;
90adcf20 927{
90adcf20 928 struct buffer *old = current_buffer;
ecf7de9b
RS
929 Lisp_Object window;
930 register struct window *w;
931 window = FRAME_SELECTED_WINDOW (f);
932 w = XWINDOW (window);
90adcf20
RS
933
934 if (update_mode_lines)
935 w->update_mode_line = Qt;
936
cf074754 937 if (
78614721 938#ifdef USE_X_TOOLKIT
cf074754 939 FRAME_EXTERNAL_MENU_BAR (f)
78614721 940#else
cf074754 941 FRAME_MENU_BAR_LINES (f) > 0
78614721 942#endif
ecf7de9b 943 )
90adcf20
RS
944 {
945 /* If the user has switched buffers or windows, we need to
946 recompute to reflect the new bindings. But we'll
947 recompute when update_mode_lines is set too; that means
948 that people can use force-mode-line-update to request
949 that the menu bar be recomputed. The adverse effect on
950 the rest of the redisplay algorithm is about the same as
951 windows_or_buffers_changed anyway. */
952 if (windows_or_buffers_changed
cf074754 953 || !NILP (w->update_mode_line)
90adcf20
RS
954 || (XFASTINT (w->last_modified) < MODIFF
955 && (XFASTINT (w->last_modified)
956 <= XBUFFER (w->buffer)->save_modified)))
957 {
958 struct buffer *prev = current_buffer;
cf074754 959 call1 (Vrun_hooks, Qmenu_bar_update_hook);
90adcf20 960 current_buffer = XBUFFER (w->buffer);
8351baf2 961 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
90adcf20 962 current_buffer = prev;
76412d64 963#ifdef USE_X_TOOLKIT
01a054bc 964 set_frame_menubar (f, 0);
76412d64 965#endif /* USE_X_TOOLKIT */
90adcf20
RS
966 }
967 }
968}
969\f
a2889657
JB
970int do_id = 1;
971
90adcf20
RS
972/* Redisplay WINDOW and its subwindows and siblings. */
973
a2889657
JB
974static void
975redisplay_windows (window)
976 Lisp_Object window;
977{
265a9e55 978 for (; !NILP (window); window = XWINDOW (window)->next)
a2889657
JB
979 redisplay_window (window, 0);
980}
981
90adcf20
RS
982/* Redisplay window WINDOW and its subwindows. */
983
a2889657
JB
984static void
985redisplay_window (window, just_this_one)
986 Lisp_Object window;
987 int just_this_one;
988{
989 register struct window *w = XWINDOW (window);
30c566e4 990 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
a2889657 991 int height;
ae3b1442 992 register int lpoint = PT;
a2889657 993 struct buffer *old = current_buffer;
b1d1124b 994 register int width = window_internal_width (w) - 1;
a2889657
JB
995 register int startp;
996 register int hscroll = XINT (w->hscroll);
997 struct position pos;
ae3b1442 998 int opoint = PT;
a2889657
JB
999 int tem;
1000 int window_needs_modeline;
1001
44fa5b1e 1002 if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
a2889657
JB
1003
1004 /* If this is a combination window, do its children; that's all. */
1005
265a9e55 1006 if (!NILP (w->vchild))
a2889657
JB
1007 {
1008 redisplay_windows (w->vchild);
1009 return;
1010 }
265a9e55 1011 if (!NILP (w->hchild))
a2889657
JB
1012 {
1013 redisplay_windows (w->hchild);
1014 return;
1015 }
265a9e55 1016 if (NILP (w->buffer))
a2889657 1017 abort ();
8de2d90b
JB
1018
1019 height = window_internal_height (w);
1020
1021 if (MINI_WINDOW_P (w))
1022 {
1023 if (w == XWINDOW (minibuf_window))
1024 {
1025 if (echo_area_glyphs)
1026 /* We've already displayed the echo area glyphs, if any. */
88f22aff 1027 goto finish_scroll_bars;
8de2d90b
JB
1028 }
1029 else
1030 {
1031 /* This is a minibuffer, but it's not the currently active one, so
1032 clear it. */
44fa5b1e 1033 int vpos = XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top);
8de2d90b
JB
1034 int i;
1035
1036 for (i = 0; i < height; i++)
1037 {
44fa5b1e 1038 get_display_line (f, vpos + i, 0);
278feba9 1039 display_string (w, vpos + i, "", 0, 0, 0, 1, 0, width);
8de2d90b
JB
1040 }
1041
88f22aff 1042 goto finish_scroll_bars;
8de2d90b
JB
1043 }
1044 }
a2889657
JB
1045
1046 if (update_mode_lines)
1047 w->update_mode_line = Qt;
1048
1049 /* Otherwise set up data on this window; select its buffer and point value */
1050
a2889657 1051 current_buffer = XBUFFER (w->buffer);
ae3b1442 1052 opoint = PT;
a2889657
JB
1053
1054 /* Count number of windows showing the selected buffer. */
1055
1056 if (!just_this_one
1057 && current_buffer == XBUFFER (XWINDOW (selected_window)->buffer))
1058 buffer_shared++;
1059
1060 /* POINT refers normally to the selected window.
1061 For any other window, set up appropriate value. */
1062
1063 if (!EQ (window, selected_window))
1064 {
1065 SET_PT (marker_position (w->pointm));
ae3b1442 1066 if (PT < BEGV)
a2889657 1067 {
265a9e55 1068 SET_PT (BEGV);
ae3b1442 1069 Fset_marker (w->pointm, make_number (PT), Qnil);
a2889657 1070 }
ae3b1442 1071 else if (PT > (ZV - 1))
a2889657 1072 {
265a9e55 1073 SET_PT (ZV);
ae3b1442 1074 Fset_marker (w->pointm, make_number (PT), Qnil);
a2889657
JB
1075 }
1076 }
1077
1078 /* If window-start is screwed up, choose a new one. */
a2889657
JB
1079 if (XMARKER (w->start)->buffer != current_buffer)
1080 goto recenter;
1081
1082 startp = marker_position (w->start);
1083
8de2d90b 1084 /* Handle case where place to start displaying has been specified,
aa6d10fa 1085 unless the specified location is outside the accessible range. */
265a9e55 1086 if (!NILP (w->force_start))
a2889657 1087 {
aa6d10fa
RS
1088 /* Forget any recorded base line for line number display. */
1089 w->base_line_number = Qnil;
a2889657
JB
1090 w->update_mode_line = Qt;
1091 w->force_start = Qnil;
1092 XFASTINT (w->last_modified) = 0;
8de2d90b
JB
1093 if (startp < BEGV) startp = BEGV;
1094 if (startp > ZV) startp = ZV;
a2889657
JB
1095 try_window (window, startp);
1096 if (cursor_vpos < 0)
1097 {
bd66d1ba 1098 /* ??? What should happen here if highlighting a region? */
a2889657
JB
1099 /* If point does not appear, move point so it does appear */
1100 pos = *compute_motion (startp, 0,
1101 ((EQ (window, minibuf_window) && startp == 1)
1102 ? minibuf_prompt_width : 0)
1103 +
1104 (hscroll ? 1 - hscroll : 0),
1105 ZV, height / 2,
1106 - (1 << (SHORTBITS - 1)),
e37f06d7 1107 width, hscroll, pos_tab_offset (w, startp), w);
a2889657 1108 SET_PT (pos.bufpos);
90adcf20 1109 if (w != XWINDOW (selected_window))
ae3b1442 1110 Fset_marker (w->pointm, make_number (PT), Qnil);
a2889657
JB
1111 else
1112 {
9d6a6bb9 1113 if (current_buffer == old)
ae3b1442 1114 lpoint = PT;
44fa5b1e
JB
1115 FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left);
1116 FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
a2889657
JB
1117 }
1118 }
1119 goto done;
1120 }
1121
1122 /* Handle case where text has not changed, only point,
44fa5b1e 1123 and it has not moved off the frame */
a2889657
JB
1124
1125 /* This code is not used for minibuffer for the sake of
1126 the case of redisplaying to replace an echo area message;
1127 since in that case the minibuffer contents per se are usually unchanged.
1128 This code is of no real use in the minibuffer since
1129 the handling of this_line_bufpos, etc.,
1130 in redisplay handles the same cases. */
1131
1132 if (XFASTINT (w->last_modified) >= MODIFF
ae3b1442 1133 && PT >= startp && !clip_changed
44fa5b1e 1134 && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
bd66d1ba
RS
1135 /* Can't use this case if highlighting a region. */
1136 && !(!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
1137 && NILP (w->region_showing)
a2889657
JB
1138 && !EQ (window, minibuf_window))
1139 {
1140 pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
ae3b1442 1141 PT, height + 1, 10000, width, hscroll,
e37f06d7 1142 pos_tab_offset (w, startp), w);
a2889657
JB
1143
1144 if (pos.vpos < height)
1145 {
44fa5b1e
JB
1146 /* Ok, point is still on frame */
1147 if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
a2889657
JB
1148 {
1149 /* These variables are supposed to be origin 1 */
44fa5b1e
JB
1150 FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left);
1151 FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
a2889657
JB
1152 }
1153 /* This doesn't do the trick, because if a window to the right of
1154 this one must be redisplayed, this does nothing because there
44fa5b1e 1155 is nothing in DesiredFrame yet, and then the other window is
a2889657 1156 redisplayed, making likes that are empty in this window's columns.
44fa5b1e 1157 if (XFASTINT (w->width) != FRAME_WIDTH (f))
a2889657
JB
1158 preserve_my_columns (w);
1159 */
1160 goto done;
1161 }
1162 /* Don't bother trying redisplay with same start;
1163 we already know it will lose */
1164 }
1165 /* If current starting point was originally the beginning of a line
1166 but no longer is, find a new starting point. */
265a9e55 1167 else if (!NILP (w->start_at_line_beg)
a2889657
JB
1168 && !(startp == BEGV
1169 || FETCH_CHAR (startp - 1) == '\n'))
1170 {
1171 goto recenter;
1172 }
1173 else if (just_this_one && !MINI_WINDOW_P (w)
ae3b1442 1174 && PT >= startp
a2889657 1175 && XFASTINT (w->last_modified)
14709f21
JB
1176 /* or else vmotion on first line won't work. */
1177 && ! NILP (w->start_at_line_beg)
a2889657
JB
1178 && ! EQ (w->window_end_valid, Qnil)
1179 && do_id && !clip_changed
1180 && !blank_end_of_window
44fa5b1e 1181 && XFASTINT (w->width) == FRAME_WIDTH (f)
bd66d1ba
RS
1182 /* Can't use this case if highlighting a region. */
1183 && !(!NILP (Vtransient_mark_mode)
1184 && !NILP (current_buffer->mark_active))
1185 && NILP (w->region_showing)
a2889657
JB
1186 && EQ (last_arrow_position, Voverlay_arrow_position)
1187 && EQ (last_arrow_string, Voverlay_arrow_string)
44fa5b1e 1188 && (tem = try_window_id (FRAME_SELECTED_WINDOW (f)))
a2889657
JB
1189 && tem != -2)
1190 {
1191 /* tem > 0 means success. tem == -1 means choose new start.
1192 tem == -2 means try again with same start,
1193 and nothing but whitespace follows the changed stuff.
1194 tem == 0 means try again with same start. */
1195 if (tem > 0)
1196 goto done;
1197 }
1198 else if (startp >= BEGV && startp <= ZV
1199 /* Avoid starting display at end of buffer! */
8de2d90b 1200 && (startp < ZV || startp == BEGV
a2889657
JB
1201 || (XFASTINT (w->last_modified) >= MODIFF)))
1202 {
1203 /* Try to redisplay starting at same place as before */
44fa5b1e 1204 /* If point has not moved off frame, accept the results */
a2889657
JB
1205 try_window (window, startp);
1206 if (cursor_vpos >= 0)
aa6d10fa
RS
1207 {
1208 if (!just_this_one || clip_changed || beg_unchanged < startp)
1209 /* Forget any recorded base line for line number display. */
1210 w->base_line_number = Qnil;
1211 goto done;
1212 }
a2889657
JB
1213 else
1214 cancel_my_columns (w);
1215 }
1216
1217 XFASTINT (w->last_modified) = 0;
1218 w->update_mode_line = Qt;
1219
1220 /* Try to scroll by specified few lines */
1221
1222 if (scroll_step && !clip_changed)
1223 {
ae3b1442 1224 if (PT > startp)
a2889657
JB
1225 {
1226 pos = *vmotion (Z - XFASTINT (w->window_end_pos),
1227 scroll_step, width, hscroll, window);
1228 if (pos.vpos >= height)
1229 goto scroll_fail;
1230 }
1231
ae3b1442 1232 pos = *vmotion (startp, PT < startp ? - scroll_step : scroll_step,
a2889657
JB
1233 width, hscroll, window);
1234
ae3b1442 1235 if (PT >= pos.bufpos)
a2889657
JB
1236 {
1237 try_window (window, pos.bufpos);
1238 if (cursor_vpos >= 0)
aa6d10fa
RS
1239 {
1240 if (!just_this_one || clip_changed || beg_unchanged < startp)
1241 /* Forget any recorded base line for line number display. */
1242 w->base_line_number = Qnil;
1243 goto done;
1244 }
a2889657
JB
1245 else
1246 cancel_my_columns (w);
1247 }
1248 scroll_fail: ;
1249 }
1250
1251 /* Finally, just choose place to start which centers point */
1252
1253recenter:
aa6d10fa
RS
1254 /* Forget any previously recorded base line for line number display. */
1255 w->base_line_number = Qnil;
1256
ae3b1442 1257 pos = *vmotion (PT, - (height / 2), width, hscroll, window);
a2889657
JB
1258 try_window (window, pos.bufpos);
1259
1260 startp = marker_position (w->start);
1261 w->start_at_line_beg =
1262 (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
1263
1264done:
265a9e55 1265 if ((!NILP (w->update_mode_line)
aa6d10fa
RS
1266 /* If window not full width, must redo its mode line
1267 if the window to its side is being redone */
1268 || (!just_this_one && width < FRAME_WIDTH (f) - 1)
1269 || INTEGERP (w->base_line_pos))
a2889657
JB
1270 && height != XFASTINT (w->height))
1271 display_mode_line (w);
aa6d10fa
RS
1272 if (! line_number_displayed
1273 && ! BUFFERP (w->base_line_pos))
1274 {
1275 w->base_line_pos = Qnil;
1276 w->base_line_number = Qnil;
1277 }
a2889657 1278
7ce2c095
RS
1279 /* When we reach a frame's selected window, redo the frame's menu bar. */
1280 if (!NILP (w->update_mode_line)
76412d64
RS
1281#ifdef USE_X_TOOLKIT
1282 && FRAME_EXTERNAL_MENU_BAR (f)
1283#else
7ce2c095 1284 && FRAME_MENU_BAR_LINES (f) > 0
76412d64 1285#endif
7ce2c095
RS
1286 && EQ (FRAME_SELECTED_WINDOW (f), window))
1287 display_menu_bar (w);
1288
88f22aff
JB
1289 finish_scroll_bars:
1290 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
30c566e4 1291 {
b1d1124b 1292 int start, end, whole;
30c566e4 1293
b1d1124b 1294 /* Calculate the start and end positions for the current window.
3505ea70
JB
1295 At some point, it would be nice to choose between scrollbars
1296 which reflect the whole buffer size, with special markers
1297 indicating narrowing, and scrollbars which reflect only the
1298 visible region.
1299
b1d1124b
JB
1300 Note that minibuffers sometimes aren't displaying any text. */
1301 if (! MINI_WINDOW_P (w)
1302 || (w == XWINDOW (minibuf_window) && ! echo_area_glyphs))
1303 {
8a9311d7 1304 whole = ZV - BEGV;
6887f623 1305 start = startp - BEGV;
b1d1124b
JB
1306 /* I don't think this is guaranteed to be right. For the
1307 moment, we'll pretend it is. */
85f26be9 1308 end = (Z - XINT (w->window_end_pos)) - BEGV;
3505ea70
JB
1309
1310 if (end < start) end = start;
8a9311d7 1311 if (whole < (end - start)) whole = end - start;
b1d1124b
JB
1312 }
1313 else
1314 start = end = whole = 0;
30c566e4 1315
88f22aff 1316 /* Indicate what this scroll bar ought to be displaying now. */
7eb9ba41 1317 (*set_vertical_scroll_bar_hook) (w, end - start, whole, start);
30c566e4 1318
88f22aff 1319 /* Note that we actually used the scroll bar attached to this window,
30c566e4 1320 so it shouldn't be deleted at the end of redisplay. */
88f22aff 1321 (*redeem_scroll_bar_hook) (w);
30c566e4 1322 }
b1d1124b
JB
1323
1324 SET_PT (opoint);
1325 current_buffer = old;
1326 SET_PT (lpoint);
a2889657
JB
1327}
1328\f
1329/* Do full redisplay on one window, starting at position `pos'. */
1330
1331static void
1332try_window (window, pos)
1333 Lisp_Object window;
1334 register int pos;
1335{
1336 register struct window *w = XWINDOW (window);
1337 register int height = window_internal_height (w);
1338 register int vpos = XFASTINT (w->top);
1339 register int last_text_vpos = vpos;
1340 int tab_offset = pos_tab_offset (w, pos);
44fa5b1e 1341 FRAME_PTR f = XFRAME (w->frame);
b1d1124b 1342 int width = window_internal_width (w) - 1;
a2889657
JB
1343 struct position val;
1344
1345 Fset_marker (w->start, make_number (pos), Qnil);
1346 cursor_vpos = -1;
1347 overlay_arrow_seen = 0;
1348 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
1349
1350 while (--height >= 0)
1351 {
1352 val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
1353 tab_offset += width;
1354 if (val.vpos) tab_offset = 0;
1355 vpos++;
1356 if (pos != val.bufpos)
1357 last_text_vpos
1358 /* Next line, unless prev line ended in end of buffer with no cr */
b0a0fbda 1359 = vpos - (val.vpos && (FETCH_CHAR (val.bufpos - 1) != '\n'
e885523c 1360#ifdef USE_TEXT_PROPERTIES
3ae8ced7 1361 || ! NILP (Fget_char_property (val.bufpos-1,
b0a0fbda 1362 Qinvisible,
3ae8ced7 1363 window))
e885523c
KH
1364#endif
1365 ));
a2889657
JB
1366 pos = val.bufpos;
1367 }
1368
1369 /* If last line is continued in middle of character,
44fa5b1e 1370 include the split character in the text considered on the frame */
a2889657
JB
1371 if (val.hpos < (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
1372 pos++;
1373
44fa5b1e 1374 /* If bottom just moved off end of frame, change mode line percentage. */
a2889657
JB
1375 if (XFASTINT (w->window_end_pos) == 0
1376 && Z != pos)
1377 w->update_mode_line = Qt;
1378
44fa5b1e 1379 /* Say where last char on frame will be, once redisplay is finished. */
a2889657
JB
1380 XFASTINT (w->window_end_pos) = Z - pos;
1381 XFASTINT (w->window_end_vpos) = last_text_vpos - XFASTINT (w->top);
1382 /* But that is not valid info until redisplay finishes. */
1383 w->window_end_valid = Qnil;
1384}
1385\f
1386/* Try to redisplay when buffer is modified locally,
1387 computing insert/delete line to preserve text outside
1388 the bounds of the changes.
1389 Return 1 if successful, 0 if if cannot tell what to do,
1390 or -1 to tell caller to find a new window start,
1391 or -2 to tell caller to do normal redisplay with same window start. */
1392
1393static int
1394try_window_id (window)
1395 Lisp_Object window;
1396{
1397 int pos;
1398 register struct window *w = XWINDOW (window);
1399 register int height = window_internal_height (w);
44fa5b1e 1400 FRAME_PTR f = XFRAME (w->frame);
a2889657
JB
1401 int top = XFASTINT (w->top);
1402 int start = marker_position (w->start);
b1d1124b 1403 int width = window_internal_width (w) - 1;
a2889657
JB
1404 int hscroll = XINT (w->hscroll);
1405 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
1406 register int vpos;
1407 register int i, tem;
1408 int last_text_vpos = 0;
1409 int stop_vpos;
9f412332
KH
1410 int selective
1411 = XTYPE (current_buffer->selective_display) == Lisp_Int
1412 ? XINT (current_buffer->selective_display)
1413 : !NILP (current_buffer->selective_display) ? -1 : 0;
a2889657
JB
1414
1415 struct position val, bp, ep, xp, pp;
1416 int scroll_amount = 0;
1417 int delta;
1418 int tab_offset, epto;
1419
1420 if (GPT - BEG < beg_unchanged)
1421 beg_unchanged = GPT - BEG;
1422 if (Z - GPT < end_unchanged)
1423 end_unchanged = Z - GPT;
1424
6a1dc7ac 1425 if (beg_unchanged + BEG < start)
a2889657
JB
1426 return 0; /* Give up if changes go above top of window */
1427
1428 /* Find position before which nothing is changed. */
1429 bp = *compute_motion (start, 0, lmargin,
6a1dc7ac 1430 min (ZV, beg_unchanged + BEG), height + 1, 0,
e37f06d7 1431 width, hscroll, pos_tab_offset (w, start), w);
a2889657 1432 if (bp.vpos >= height)
6e8290aa 1433 {
ae3b1442 1434 if (PT < bp.bufpos && !bp.contin)
6e8290aa 1435 {
44fa5b1e
JB
1436 /* All changes are below the frame, and point is on the frame.
1437 We don't need to change the frame at all.
6e8290aa
JB
1438 But we need to update window_end_pos to account for
1439 any change in buffer size. */
f7be7f78
JB
1440 bp = *compute_motion (start, 0, lmargin,
1441 Z, height, 0,
e37f06d7 1442 width, hscroll, pos_tab_offset (w, start), w);
6e8290aa
JB
1443 XFASTINT (w->window_end_vpos) = height;
1444 XFASTINT (w->window_end_pos) = Z - bp.bufpos;
1445 return 1;
1446 }
1447 return 0;
1448 }
a2889657
JB
1449
1450 vpos = bp.vpos;
1451
44fa5b1e 1452 /* Find beginning of that frame line. Must display from there. */
a2889657
JB
1453 bp = *vmotion (bp.bufpos, 0, width, hscroll, window);
1454
1455 pos = bp.bufpos;
1456 val.hpos = lmargin;
1457 if (pos < start)
1458 return -1;
1459
1460 /* If about to start displaying at the beginning of a continuation line,
44fa5b1e 1461 really start with previous frame line, in case it was not
a2889657 1462 continued when last redisplayed */
05ba02eb
JB
1463 if ((bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0)
1464 ||
1465 /* Likewise if we have to worry about selective display. */
9f412332 1466 (selective > 0 && bp.bufpos - 1 == beg_unchanged && vpos > 0))
a2889657
JB
1467 {
1468 bp = *vmotion (bp.bufpos, -1, width, hscroll, window);
1469 --vpos;
1470 pos = bp.bufpos;
1471 }
1472
1473 if (bp.contin && bp.hpos != lmargin)
1474 {
1475 val.hpos = bp.prevhpos - width + lmargin;
1476 pos--;
1477 }
1478
1479 bp.vpos = vpos;
1480
1481 /* Find first visible newline after which no more is changed. */
1482 tem = find_next_newline (Z - max (end_unchanged, Z - ZV), 1);
9f412332
KH
1483 if (selective > 0)
1484 while (tem < ZV - 1 && (indented_beyond_p (tem, selective)))
a2889657
JB
1485 tem = find_next_newline (tem, 1);
1486
1487 /* Compute the cursor position after that newline. */
1488 ep = *compute_motion (pos, vpos, val.hpos, tem,
1489 height, - (1 << (SHORTBITS - 1)),
e37f06d7 1490 width, hscroll, pos_tab_offset (w, bp.bufpos), w);
a2889657 1491
44fa5b1e
JB
1492 /* If changes reach past the text available on the frame,
1493 just display rest of frame. */
a2889657
JB
1494 if (ep.bufpos > Z - XFASTINT (w->window_end_pos))
1495 stop_vpos = height;
1496 else
1497 stop_vpos = ep.vpos;
1498
1499 /* If no newline before ep, the line ep is on includes some changes
1500 that must be displayed. Make sure we don't stop before it. */
1501 /* Also, if changes reach all the way until ep.bufpos,
1502 it is possible that something was deleted after the
1503 newline before it, so the following line must be redrawn. */
1504 if (stop_vpos == ep.vpos
1505 && (ep.bufpos == BEGV
1506 || FETCH_CHAR (ep.bufpos - 1) != '\n'
1507 || ep.bufpos == Z - end_unchanged))
1508 stop_vpos = ep.vpos + 1;
1509
1510 cursor_vpos = -1;
1511 overlay_arrow_seen = 0;
1512
1513 /* If changes do not reach to bottom of window,
1514 figure out how much to scroll the rest of the window */
1515 if (stop_vpos < height)
1516 {
1517 /* Now determine how far up or down the rest of the window has moved */
1518 epto = pos_tab_offset (w, ep.bufpos);
1519 xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
1520 Z - XFASTINT (w->window_end_pos),
e37f06d7 1521 10000, 0, width, hscroll, epto, w);
a2889657
JB
1522 scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
1523
44fa5b1e 1524 /* Is everything on frame below the changes whitespace?
a2889657
JB
1525 If so, no scrolling is really necessary. */
1526 for (i = ep.bufpos; i < xp.bufpos; i++)
1527 {
1528 tem = FETCH_CHAR (i);
1529 if (tem != ' ' && tem != '\n' && tem != '\t')
1530 break;
1531 }
1532 if (i == xp.bufpos)
1533 return -2;
1534
1535 XFASTINT (w->window_end_vpos) += scroll_amount;
1536
44fa5b1e 1537 /* Before doing any scrolling, verify that point will be on frame. */
ae3b1442 1538 if (PT > ep.bufpos && !(PT <= xp.bufpos && xp.bufpos < height))
a2889657 1539 {
ae3b1442 1540 if (PT <= xp.bufpos)
a2889657
JB
1541 {
1542 pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
ae3b1442 1543 PT, height, - (1 << (SHORTBITS - 1)),
e37f06d7 1544 width, hscroll, epto, w);
a2889657
JB
1545 }
1546 else
1547 {
1548 pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
ae3b1442 1549 PT, height, - (1 << (SHORTBITS - 1)),
e37f06d7
KH
1550 width, hscroll,
1551 pos_tab_offset (w, xp.bufpos), w);
a2889657 1552 }
ae3b1442 1553 if (pp.bufpos < PT || pp.vpos == height)
a2889657
JB
1554 return 0;
1555 cursor_vpos = pp.vpos + top;
1556 cursor_hpos = pp.hpos + XFASTINT (w->left);
1557 }
1558
1559 if (stop_vpos - scroll_amount >= height
1560 || ep.bufpos == xp.bufpos)
1561 {
1562 if (scroll_amount < 0)
1563 stop_vpos -= scroll_amount;
1564 scroll_amount = 0;
1565 /* In this path, we have altered window_end_vpos
1566 and not left it negative.
1567 We must make sure that, in case display is preempted
44fa5b1e 1568 before the frame changes to reflect what we do here,
a2889657 1569 further updates will not come to try_window_id
44fa5b1e 1570 and assume the frame and window_end_vpos match. */
a2889657
JB
1571 blank_end_of_window = 1;
1572 }
1573 else if (!scroll_amount)
0d231165
RS
1574 {
1575 /* Even if we don't need to scroll, we must adjust the
1576 charstarts of subsequent lines (that we won't redisplay)
1577 according to the amount of text inserted or deleted. */
1578 int oldpos = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0];
1579 int adjust = ep.bufpos - oldpos;
1580 adjust_window_charstarts (w, ep.vpos + top - 1, adjust);
1581 }
a2889657
JB
1582 else if (bp.bufpos == Z - end_unchanged)
1583 {
1584 /* If reprinting everything is nearly as fast as scrolling,
1585 don't bother scrolling. Can happen if lines are short. */
44fa5b1e 1586 if (scroll_cost (f, bp.vpos + top - scroll_amount,
a2889657
JB
1587 top + height - max (0, scroll_amount),
1588 scroll_amount)
1589 > xp.bufpos - bp.bufpos - 20)
1590 /* Return "try normal display with same window-start."
1591 Too bad we can't prevent further scroll-thinking. */
1592 return -2;
1593 /* If pure deletion, scroll up as many lines as possible.
1594 In common case of killing a line, this can save the
1595 following line from being overwritten by scrolling
1596 and therefore having to be redrawn. */
44fa5b1e 1597 tem = scroll_frame_lines (f, bp.vpos + top - scroll_amount,
d1cb44a4
RS
1598 top + height - max (0, scroll_amount),
1599 scroll_amount, bp.bufpos);
d2f84654
RS
1600 if (!tem)
1601 stop_vpos = height;
1602 else
1603 {
1604 /* scroll_frame_lines did not properly adjust subsequent
1605 lines' charstarts in the case where the text of the
1606 screen line at bp.vpos has changed.
1607 (This can happen in a deletion that ends in mid-line.)
1608 To adjust properly, we need to make things constent at
1609 the position ep.
1610 So do a second adjust to make that happen.
1611 Note that stop_vpos >= ep.vpos, so it is sufficient
1612 to update the charstarts for lines at ep.vpos and below. */
1613 int oldstart
1614 = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0];
1615 adjust_window_charstarts (w, ep.vpos + top - 1,
1616 ep.bufpos - oldstart);
1617 }
a2889657
JB
1618 }
1619 else if (scroll_amount)
1620 {
1621 /* If reprinting everything is nearly as fast as scrolling,
1622 don't bother scrolling. Can happen if lines are short. */
1623 /* Note that if scroll_amount > 0, xp.bufpos - bp.bufpos is an
1624 overestimate of cost of reprinting, since xp.bufpos
1625 would end up below the bottom of the window. */
44fa5b1e 1626 if (scroll_cost (f, ep.vpos + top - scroll_amount,
a2889657
JB
1627 top + height - max (0, scroll_amount),
1628 scroll_amount)
1629 > xp.bufpos - ep.bufpos - 20)
1630 /* Return "try normal display with same window-start."
1631 Too bad we can't prevent further scroll-thinking. */
1632 return -2;
44fa5b1e 1633 tem = scroll_frame_lines (f, ep.vpos + top - scroll_amount,
a2889657 1634 top + height - max (0, scroll_amount),
d1cb44a4 1635 scroll_amount, ep.bufpos);
a2889657
JB
1636 if (!tem) stop_vpos = height;
1637 }
1638 }
1639
1640 /* In any case, do not display past bottom of window */
1641 if (stop_vpos >= height)
1642 {
1643 stop_vpos = height;
1644 scroll_amount = 0;
1645 }
1646
1647 /* Handle case where pos is before w->start --
1648 can happen if part of line had been clipped and is not clipped now */
1649 if (vpos == 0 && pos < marker_position (w->start))
1650 Fset_marker (w->start, make_number (pos), Qnil);
1651
1652 /* Redisplay the lines where the text was changed */
1653 last_text_vpos = vpos;
1654 tab_offset = pos_tab_offset (w, pos);
1655 /* If we are starting display in mid-character, correct tab_offset
1656 to account for passing the line that that character really starts in. */
1657 if (val.hpos < lmargin)
1658 tab_offset += width;
1659 while (vpos < stop_vpos)
1660 {
1661 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
1662 tab_offset += width;
1663 if (val.vpos) tab_offset = 0;
1664 if (pos != val.bufpos)
1665 last_text_vpos
1666 /* Next line, unless prev line ended in end of buffer with no cr */
1667 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
1668 pos = val.bufpos;
1669 }
1670
1671 /* There are two cases:
1672 1) we have displayed down to the bottom of the window
1673 2) we have scrolled lines below stop_vpos by scroll_amount */
1674
1675 if (vpos == height)
1676 {
1677 /* If last line is continued in middle of character,
44fa5b1e 1678 include the split character in the text considered on the frame */
a2889657
JB
1679 if (val.hpos < lmargin)
1680 val.bufpos++;
1681 XFASTINT (w->window_end_vpos) = last_text_vpos;
1682 XFASTINT (w->window_end_pos) = Z - val.bufpos;
1683 }
1684
1685 /* If scrolling made blank lines at window bottom,
1686 redisplay to fill those lines */
1687 if (scroll_amount < 0)
1688 {
1689 /* Don't consider these lines for general-purpose scrolling.
1690 That will save time in the scrolling computation. */
44fa5b1e 1691 FRAME_SCROLL_BOTTOM_VPOS (f) = xp.vpos;
a2889657
JB
1692 vpos = xp.vpos;
1693 pos = xp.bufpos;
1694 val.hpos = lmargin;
1695 if (pos == ZV)
1696 vpos = height + scroll_amount;
1697 else if (xp.contin && xp.hpos != lmargin)
1698 {
1699 val.hpos = xp.prevhpos - width + lmargin;
1700 pos--;
1701 }
1702
1703 blank_end_of_window = 1;
1704 tab_offset = pos_tab_offset (w, pos);
1705 /* If we are starting display in mid-character, correct tab_offset
1706 to account for passing the line that that character starts in. */
1707 if (val.hpos < lmargin)
1708 tab_offset += width;
1709
1710 while (vpos < height)
1711 {
1712 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
1713 tab_offset += width;
1714 if (val.vpos) tab_offset = 0;
1715 pos = val.bufpos;
1716 }
1717
1718 /* Here is a case where display_text_line sets cursor_vpos wrong.
1719 Make it be fixed up, below. */
1720 if (xp.bufpos == ZV
ae3b1442 1721 && xp.bufpos == PT)
a2889657
JB
1722 cursor_vpos = -1;
1723 }
1724
44fa5b1e 1725 /* If bottom just moved off end of frame, change mode line percentage. */
a2889657
JB
1726 if (XFASTINT (w->window_end_pos) == 0
1727 && Z != val.bufpos)
1728 w->update_mode_line = Qt;
1729
1730 /* Attempt to adjust end-of-text positions to new bottom line */
1731 if (scroll_amount)
1732 {
1733 delta = height - xp.vpos;
1734 if (delta < 0
1735 || (delta > 0 && xp.bufpos <= ZV)
1736 || (delta == 0 && xp.hpos))
1737 {
1738 val = *vmotion (Z - XFASTINT (w->window_end_pos),
1739 delta, width, hscroll, window);
1740 XFASTINT (w->window_end_pos) = Z - val.bufpos;
1741 XFASTINT (w->window_end_vpos) += val.vpos;
1742 }
1743 }
1744
1745 w->window_end_valid = Qnil;
1746
1747 /* If point was not in a line that was displayed, find it */
1748 if (cursor_vpos < 0)
1749 {
ae3b1442 1750 val = *compute_motion (start, 0, lmargin, PT, 10000, 10000,
e37f06d7 1751 width, hscroll, pos_tab_offset (w, start), w);
44fa5b1e 1752 /* Admit failure if point is off frame now */
a2889657
JB
1753 if (val.vpos >= height)
1754 {
1755 for (vpos = 0; vpos < height; vpos++)
44fa5b1e 1756 cancel_line (vpos + top, f);
a2889657
JB
1757 return 0;
1758 }
1759 cursor_vpos = val.vpos + top;
1760 cursor_hpos = val.hpos + XFASTINT (w->left);
1761 }
1762
44fa5b1e
JB
1763 FRAME_CURSOR_X (f) = max (0, cursor_hpos);
1764 FRAME_CURSOR_Y (f) = cursor_vpos;
a2889657
JB
1765
1766 if (debug_end_pos)
1767 {
1768 val = *compute_motion (start, 0, lmargin, ZV,
1769 height, - (1 << (SHORTBITS - 1)),
e37f06d7 1770 width, hscroll, pos_tab_offset (w, start), w);
a2889657
JB
1771 if (val.vpos != XFASTINT (w->window_end_vpos))
1772 abort ();
1773 if (XFASTINT (w->window_end_pos)
1774 != Z - val.bufpos)
1775 abort ();
1776 }
1777
1778 return 1;
1779}
1780\f
31b24551
JB
1781/* Mark a section of BUF as modified, but only for the sake of redisplay.
1782 This is useful for recording changes to overlays.
1783
1784 We increment the buffer's modification timestamp and set the
1785 redisplay caches (windows_or_buffers_changed, beg_unchanged, etc)
1786 as if the region of text between START and END had been modified;
1787 the redisplay code will check this against the windows' timestamps,
1788 and redraw the appropriate area of the buffer.
1789
1790 However, if the buffer is unmodified, we bump the last-save
1791 timestamp as well, so that incrementing the timestamp doesn't fool
1792 Emacs into thinking that the buffer's text has been modified.
1793
1794 Tweaking the timestamps shouldn't hurt the first-modification
1795 timestamps recorded in the undo records; those values aren't
1796 written until just before a real text modification is made, so they
1797 will never catch the timestamp value just before this function gets
1798 called. */
1799
1800void
1801redisplay_region (buf, start, end)
1802 struct buffer *buf;
1803 int start, end;
1804{
1805 if (start == end)
1806 return;
1807
1808 if (start > end)
1809 {
1810 int temp = start;
1811 start = end; end = temp;
1812 }
1813
1814 if (buf != current_buffer)
1815 windows_or_buffers_changed = 1;
1816 else
1817 {
1818 if (unchanged_modified == MODIFF)
1819 {
1820 beg_unchanged = start - BEG;
1821 end_unchanged = Z - end;
1822 }
1823 else
1824 {
1825 if (Z - end < end_unchanged)
1826 end_unchanged = Z - end;
1827 if (start - BEG < beg_unchanged)
1828 beg_unchanged = start - BEG;
1829 }
1830 }
1831
1832 /* Increment the buffer's time stamp, but also increment the save
1833 and autosave timestamps, so as not to screw up that timekeeping. */
1834 if (BUF_MODIFF (buf) == buf->save_modified)
1835 buf->save_modified++;
1836 if (BUF_MODIFF (buf) == buf->auto_save_modified)
1837 buf->auto_save_modified++;
1838
1839 BUF_MODIFF (buf) ++;
1840}
1841
1842\f
278feba9 1843/* Copy LEN glyphs starting address FROM to the rope TO.
f7430cb6 1844 But don't actually copy the parts that would come in before S.
278feba9
RS
1845 Value is TO, advanced past the copied data.
1846 F is the frame we are displaying in. */
a2889657 1847
278feba9
RS
1848static GLYPH *
1849copy_part_of_rope (f, to, s, from, len, face)
1850 FRAME_PTR f;
1851 register GLYPH *to; /* Copy to here. */
a2889657 1852 register GLYPH *s; /* Starting point. */
278feba9
RS
1853 Lisp_Object *from; /* Data to copy. */
1854 int len;
1c2250c2 1855 int face; /* Face to apply to glyphs which don't specify one. */
a2889657 1856{
278feba9
RS
1857 int n = len;
1858 register Lisp_Object *fp = from;
1859 /* These cache the results of the last call to compute_glyph_face. */
1860 int last_code = -1;
1861 int last_merged = 0;
c581d710 1862
4cdc65eb
KH
1863#ifdef HAVE_X_WINDOWS
1864 if (! FRAME_TERMCAP_P (f))
1865 while (n--)
1866 {
dedd1182 1867 int glyph = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
4cdc65eb
KH
1868 int facecode;
1869
1870 if (FAST_GLYPH_FACE (glyph) == 0)
1871 /* If GLYPH has no face code, use FACE. */
1872 facecode = face;
1873 else if (FAST_GLYPH_FACE (glyph) == last_code)
1874 /* If it's same as previous glyph, use same result. */
1875 facecode = last_merged;
1876 else
1877 {
1878 /* Merge this glyph's face and remember the result. */
1879 last_code = FAST_GLYPH_FACE (glyph);
1880 last_merged = facecode = compute_glyph_face (f, last_code, face);
1881 }
b2a76982 1882
4cdc65eb
KH
1883 if (to >= s)
1884 *to = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), facecode);
1885 ++to;
1886 ++fp;
1887 }
1888 else
1889#endif
1890 while (n--)
1891 {
dedd1182 1892 if (to >= s) *to = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
4cdc65eb
KH
1893 ++to;
1894 ++fp;
1895 }
278feba9 1896 return to;
c581d710
RS
1897}
1898
278feba9
RS
1899/* Correct a glyph by replacing its specified user-level face code
1900 with a displayable computed face code. */
c581d710 1901
278feba9 1902static GLYPH
659a218f 1903fix_glyph (f, glyph, cface)
278feba9
RS
1904 FRAME_PTR f;
1905 GLYPH glyph;
659a218f 1906 int cface;
c581d710 1907{
4cdc65eb 1908#ifdef HAVE_X_WINDOWS
659a218f
KH
1909 if (! FRAME_TERMCAP_P (f))
1910 {
1911 if (FAST_GLYPH_FACE (glyph) != 0)
1912 cface = compute_glyph_face (f, FAST_GLYPH_FACE (glyph), cface);
1913 glyph = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), cface);
1914 }
4cdc65eb
KH
1915#endif
1916 return glyph;
a2889657
JB
1917}
1918\f
1919/* Display one line of window w, starting at position START in W's buffer.
1920 Display starting at horizontal position HPOS, which is normally zero
1921 or negative. A negative value causes output up to hpos = 0 to be discarded.
1922 This is done for negative hscroll, or when this is a continuation line
1923 and the continuation occurred in the middle of a multi-column character.
1924
1925 TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
1926
44fa5b1e 1927 Display on position VPOS on the frame. (origin 0).
a2889657
JB
1928
1929 Returns a STRUCT POSITION giving character to start next line with
1930 and where to display it, including a zero or negative hpos.
1931 The vpos field is not really a vpos; it is 1 unless the line is continued */
1932
1933struct position val_display_text_line;
1934
1935static struct position *
1936display_text_line (w, start, vpos, hpos, taboffset)
1937 struct window *w;
1938 int start;
1939 int vpos;
1940 int hpos;
1941 int taboffset;
1942{
1943 register int pos = start;
1944 register int c;
1945 register GLYPH *p1;
1946 int end;
1947 register int pause;
1948 register unsigned char *p;
1949 GLYPH *endp;
d2f84654 1950 register GLYPH *leftmargin;
5fcbb24d 1951 register GLYPH *p1prev = 0;
efc63ef0
RS
1952 register GLYPH *p1start;
1953 int *charstart;
44fa5b1e 1954 FRAME_PTR f = XFRAME (w->frame);
a2889657 1955 int tab_width = XINT (current_buffer->tab_width);
265a9e55 1956 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
b1d1124b 1957 int width = window_internal_width (w) - 1;
a2889657
JB
1958 struct position val;
1959 int lastpos;
1960 int invis;
1961 int hscroll = XINT (w->hscroll);
d2f84654
RS
1962 int truncate = (hscroll
1963 || (truncate_partial_width_windows
1964 && XFASTINT (w->width) < FRAME_WIDTH (f))
1965 || !NILP (current_buffer->truncate_lines));
bd66d1ba
RS
1966
1967 /* 1 if we should highlight the region. */
1968 int highlight_region
1969 = !NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active);
1970 int region_beg, region_end;
1971
a2889657
JB
1972 int selective
1973 = XTYPE (current_buffer->selective_display) == Lisp_Int
1974 ? XINT (current_buffer->selective_display)
265a9e55 1975 : !NILP (current_buffer->selective_display) ? -1 : 0;
44fa5b1e 1976 register struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
a2889657 1977 register struct Lisp_Vector *dp = window_display_table (w);
68a37fa8
RS
1978
1979 Lisp_Object default_invis_vector[3];
1980 /* Nonzero means display something where there are invisible lines.
1981 The precise value is the number of glyphs to display. */
a2889657 1982 int selective_rlen
c581d710 1983 = (selective && dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector
68a37fa8
RS
1984 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size
1985 : selective && !NILP (current_buffer->selective_display_ellipses)
1986 ? 3 : 0);
1987 /* This is the sequence of Lisp objects to display
1988 when there are invisible lines. */
1989 Lisp_Object *invis_vector_contents
1990 = (dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector
1991 ? XVECTOR (DISP_INVIS_VECTOR (dp))->contents
1992 : default_invis_vector);
1993
a2889657 1994 GLYPH truncator = (dp == 0 || XTYPE (DISP_TRUNC_GLYPH (dp)) != Lisp_Int
278feba9 1995 ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
a2889657 1996 GLYPH continuer = (dp == 0 || XTYPE (DISP_CONTINUE_GLYPH (dp)) != Lisp_Int
278feba9 1997 ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
a2889657 1998
31b24551
JB
1999 /* The next buffer location at which the face should change, due
2000 to overlays or text property changes. */
2001 int next_face_change;
2002
b0a0fbda
RS
2003#ifdef USE_TEXT_PROPERTIES
2004 /* The next location where the `invisible' property changes */
2005 int next_invisible;
b0a0fbda
RS
2006#endif
2007
31b24551 2008 /* The face we're currently using. */
1c2250c2 2009 int current_face = 0;
efc63ef0 2010 int i;
31b24551 2011
68a37fa8
RS
2012 XFASTINT (default_invis_vector[2]) = '.';
2013 default_invis_vector[0] = default_invis_vector[1] = default_invis_vector[2];
2014
a2889657 2015 hpos += XFASTINT (w->left);
44fa5b1e 2016 get_display_line (f, vpos, XFASTINT (w->left));
54ff581a 2017 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
a2889657 2018
bd66d1ba 2019 /* Show where to highlight the region. */
1613b757 2020 if (highlight_region && XMARKER (current_buffer->mark)->buffer != 0
fba9ce76
RS
2021 /* Maybe highlight only in selected window. */
2022 && (highlight_nonselected_windows
6f139a45 2023 || w == XWINDOW (selected_window)))
bd66d1ba
RS
2024 {
2025 region_beg = marker_position (current_buffer->mark);
2026 if (PT < region_beg)
2027 {
2028 region_end = region_beg;
2029 region_beg = PT;
2030 }
2031 else
2032 region_end = PT;
2033 w->region_showing = Qt;
2034 }
2035 else
2036 region_beg = region_end = -1;
2037
a2889657
JB
2038 if (MINI_WINDOW_P (w) && start == 1
2039 && vpos == XFASTINT (w->top))
2040 {
2041 if (minibuf_prompt)
f7b4b63a
KH
2042 {
2043 minibuf_prompt_width
2044 = (display_string (w, vpos, minibuf_prompt, -1, hpos,
a2889657 2045 (!truncate ? continuer : truncator),
f7b4b63a
KH
2046 1, -1, -1)
2047 - hpos);
2048 hpos += minibuf_prompt_width;
2049 }
2050 else
2051 minibuf_prompt_width = 0;
a2889657
JB
2052 }
2053
2054 desired_glyphs->bufp[vpos] = pos;
2055 p1 = desired_glyphs->glyphs[vpos] + hpos;
efc63ef0
RS
2056 p1start = p1;
2057 charstart = desired_glyphs->charstarts[vpos] + hpos;
2058 /* In case we don't ever write anything into it... */
a007eef6 2059 desired_glyphs->charstarts[vpos][XFASTINT (w->left)] = -1;
a2889657 2060 end = ZV;
d2f84654
RS
2061 leftmargin = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
2062 endp = leftmargin + width;
a2889657 2063
1c2250c2
JB
2064 /* Arrange the overlays nicely for our purposes. Usually, we call
2065 display_text_line on only one line at a time, in which case this
2066 can't really hurt too much, or we call it on lines which appear
2067 one after another in the buffer, in which case all calls to
2068 recenter_overlay_lists but the first will be pretty cheap. */
2069 recenter_overlay_lists (current_buffer, pos);
2070
a2889657
JB
2071 /* Loop generating characters.
2072 Stop at end of buffer, before newline,
31b24551
JB
2073 if reach or pass continuation column,
2074 or at face change. */
a2889657 2075 pause = pos;
31b24551 2076 next_face_change = pos;
b0a0fbda
RS
2077#ifdef USE_TEXT_PROPERTIES
2078 next_invisible = pos;
2079#endif
85bcef6c 2080 while (1)
a2889657 2081 {
efc63ef0
RS
2082 /* Record which glyph starts a character,
2083 and the character position of that character. */
d2f84654 2084 if (p1 >= leftmargin)
853cf346 2085 charstart[p1 - p1start] = pos;
efc63ef0 2086
85bcef6c
RS
2087 if (p1 >= endp)
2088 break;
2089
a2889657 2090 p1prev = p1;
31b24551 2091 if (pos >= pause)
a2889657 2092 {
31b24551
JB
2093 /* Did we hit the end of the visible region of the buffer?
2094 Stop here. */
2095 if (pos >= end)
a2889657 2096 break;
31b24551
JB
2097
2098 /* Did we reach point? Record the cursor location. */
ae3b1442 2099 if (pos == PT && cursor_vpos < 0)
a2889657
JB
2100 {
2101 cursor_vpos = vpos;
d2f84654 2102 cursor_hpos = p1 - leftmargin;
a2889657
JB
2103 }
2104
b0a0fbda
RS
2105#ifdef USE_TEXT_PROPERTIES
2106 /* if the `invisible' property is set to t, we can skip to
2107 the next property change */
2108 while (pos == next_invisible && pos < end)
b0a0fbda 2109 {
3ae8ced7 2110 Lisp_Object position, limit, endpos, prop, ww;
dfabd9a0 2111 XFASTINT (position) = pos;
3ae8ced7
KH
2112 XSET (ww, Lisp_Window, w);
2113 prop = Fget_char_property (position, Qinvisible, ww);
dfabd9a0
RS
2114 /* This is just an estimate to give reasonable
2115 performance; nothing should go wrong if it is too small. */
fe3d6921
KH
2116 limit = Fnext_overlay_change (position);
2117 if (XFASTINT (limit) > pos + 50)
2118 XFASTINT (limit) = pos + 50;
2119 endpos = Fnext_single_property_change (position, Qinvisible,
dfabd9a0
RS
2120 Fcurrent_buffer (), limit);
2121 if (INTEGERP (endpos))
2122 next_invisible = XINT (endpos);
2123 else
2124 next_invisible = end;
2125 if (! NILP (prop))
2126 {
ae3b1442 2127 if (pos < PT && next_invisible >= PT)
dfabd9a0
RS
2128 {
2129 cursor_vpos = vpos;
d2f84654 2130 cursor_hpos = p1 - leftmargin;
dfabd9a0
RS
2131 }
2132 pos = next_invisible;
2133 }
b0a0fbda 2134 }
b0a0fbda
RS
2135 if (pos >= end)
2136 break;
2137#endif
2138
9dbd4b48 2139#ifdef HAVE_X_WINDOWS
31b24551
JB
2140 /* Did we hit a face change? Figure out what face we should
2141 use now. We also hit this the first time through the
2142 loop, to see what face we should start with. */
b0a0fbda 2143 if (pos >= next_face_change && FRAME_X_P (f))
bd66d1ba
RS
2144 current_face = compute_char_face (f, w, pos,
2145 region_beg, region_end,
efc63ef0 2146 &next_face_change, pos + 50, 0);
9dbd4b48 2147#endif
31b24551 2148
1c2250c2
JB
2149 pause = end;
2150
b0a0fbda
RS
2151#ifdef USE_TEXT_PROPERTIES
2152 if (pos < next_invisible && next_invisible < pause)
2153 pause = next_invisible;
2154#endif
1c2250c2
JB
2155 if (pos < next_face_change && next_face_change < pause)
2156 pause = next_face_change;
2157
31b24551
JB
2158 /* Wouldn't you hate to read the next line to someone over
2159 the phone? */
ae3b1442
KH
2160 if (pos < PT && PT < pause)
2161 pause = PT;
a2889657
JB
2162 if (pos < GPT && GPT < pause)
2163 pause = GPT;
2164
2165 p = &FETCH_CHAR (pos);
2166 }
2167 c = *p++;
2168 if (c >= 040 && c < 0177
c581d710 2169 && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
a2889657 2170 {
d2f84654 2171 if (p1 >= leftmargin)
4cdc65eb 2172 *p1 = MAKE_GLYPH (f, c, current_face);
a2889657
JB
2173 p1++;
2174 }
2175 else if (c == '\n')
2176 {
2177 invis = 0;
d6f08da4 2178 while (pos + 1 < end
a2889657 2179 && selective > 0
9f412332 2180 && indented_beyond_p (pos + 1, selective))
a2889657
JB
2181 {
2182 invis = 1;
2183 pos = find_next_newline (pos + 1, 1);
2184 if (FETCH_CHAR (pos - 1) == '\n')
2185 pos--;
2186 }
d2f84654 2187 if (invis && selective_rlen > 0 && p1 >= leftmargin)
a2889657
JB
2188 {
2189 p1 += selective_rlen;
d2f84654 2190 if (p1 - leftmargin > width)
a2889657 2191 p1 = endp;
278feba9 2192 copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
1c2250c2 2193 (p1 - p1prev), current_face);
a2889657 2194 }
4cdc65eb 2195#ifdef HAVE_X_WINDOWS
3c5c35c5
JB
2196 /* Draw the face of the newline character as extending all the
2197 way to the end of the frame line. */
2198 if (current_face)
2199 while (p1 < endp)
4cdc65eb 2200 *p1++ = FAST_MAKE_GLYPH (' ', current_face);
3c5c35c5 2201#endif
68a37fa8 2202 break;
a2889657
JB
2203 }
2204 else if (c == '\t')
2205 {
2206 do
2207 {
d2f84654 2208 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2209 *p1 = MAKE_GLYPH (f, ' ', current_face);
a2889657
JB
2210 p1++;
2211 }
d2f84654 2212 while ((p1 - leftmargin + taboffset + hscroll - (hscroll > 0))
a2889657
JB
2213 % tab_width);
2214 }
6e8290aa 2215 else if (c == Ctl ('M') && selective == -1)
a2889657
JB
2216 {
2217 pos = find_next_newline (pos, 1);
2218 if (FETCH_CHAR (pos - 1) == '\n')
2219 pos--;
2220 if (selective_rlen > 0)
2221 {
2222 p1 += selective_rlen;
d2f84654 2223 if (p1 - leftmargin > width)
a2889657 2224 p1 = endp;
278feba9 2225 copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
1c2250c2 2226 (p1 - p1prev), current_face);
a2889657 2227 }
4cdc65eb 2228#ifdef HAVE_X_WINDOWS
3c5c35c5
JB
2229 /* Draw the face of the newline character as extending all the
2230 way to the end of the frame line. */
2231 if (current_face)
2232 while (p1 < endp)
4cdc65eb 2233 *p1++ = FAST_MAKE_GLYPH (' ', current_face);
3c5c35c5 2234#endif
68a37fa8 2235 break;
a2889657 2236 }
c581d710 2237 else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
a2889657 2238 {
d2f84654 2239 p1 = copy_part_of_rope (f, p1, leftmargin,
278feba9
RS
2240 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
2241 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
2242 current_face);
a2889657
JB
2243 }
2244 else if (c < 0200 && ctl_arrow)
2245 {
d2f84654 2246 if (p1 >= leftmargin)
278feba9
RS
2247 *p1 = fix_glyph (f, (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
2248 ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
2249 current_face);
a2889657 2250 p1++;
d2f84654 2251 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2252 *p1 = MAKE_GLYPH (f, c ^ 0100, current_face);
a2889657
JB
2253 p1++;
2254 }
2255 else
2256 {
d2f84654 2257 if (p1 >= leftmargin)
278feba9
RS
2258 *p1 = fix_glyph (f, (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
2259 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
2260 current_face);
a2889657 2261 p1++;
d2f84654 2262 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2263 *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face);
a2889657 2264 p1++;
d2f84654 2265 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2266 *p1 = MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face);
a2889657 2267 p1++;
d2f84654 2268 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2269 *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face);
a2889657
JB
2270 p1++;
2271 }
31b24551 2272
853cf346 2273 /* Do nothing here for a char that's entirely off the left edge. */
d2f84654 2274 if (p1 >= leftmargin)
efc63ef0 2275 {
853cf346
RS
2276 /* For all the glyphs occupied by this character, except for the
2277 first, store -1 in charstarts. */
2278 if (p1 != p1prev)
2279 {
2280 int *p2x = &charstart[p1prev - p1start];
2281 int *p2 = &charstart[p1 - p1start];
2282
2283 /* The window's left column should always
2284 contain a character position.
2285 And don't clobber anything to the left of that. */
d2f84654 2286 if (p1prev < leftmargin)
853cf346 2287 {
a007eef6
RS
2288 p2x = charstart + (leftmargin - p1start);
2289 *p2x = pos;
853cf346
RS
2290 }
2291
2292 /* This loop skips over the char p2x initially points to. */
a007eef6 2293 while (++p2x < p2)
853cf346
RS
2294 *p2x = -1;
2295 }
efc63ef0 2296 }
853cf346 2297
a2889657
JB
2298 pos++;
2299 }
2300
2301 val.hpos = - XINT (w->hscroll);
2302 if (val.hpos)
2303 val.hpos++;
2304
2305 val.vpos = 1;
2306
2307 lastpos = pos;
2308
efc63ef0
RS
2309 /* Store 0 in this charstart line for the positions where
2310 there is no character. But do leave what was recorded
2311 for the character that ended the line. */
85bcef6c
RS
2312 /* Add 1 in the endtest to compensate for the fact that ENDP was
2313 made from WIDTH, which is 1 less than the window's actual
2314 internal width. */
a007eef6
RS
2315 i = p1 - p1start + 1;
2316 if (p1 < leftmargin)
2317 i += leftmargin - p1;
2318 for (; i < endp - p1start + 1; i++)
efc63ef0
RS
2319 charstart[i] = 0;
2320
a2889657
JB
2321 /* Handle continuation in middle of a character */
2322 /* by backing up over it */
2323 if (p1 > endp)
2324 {
5fcbb24d
JB
2325 /* Don't back up if we never actually displayed any text.
2326 This occurs when the minibuffer prompt takes up the whole line. */
2327 if (p1prev)
2328 {
2329 /* Start the next line with that same character */
2330 pos--;
2331 /* but at negative hpos, to skip the columns output on this line. */
2332 val.hpos += p1prev - endp;
2333 }
2334
a2889657
JB
2335 /* Keep in this line everything up to the continuation column. */
2336 p1 = endp;
2337 }
2338
2339 /* Finish deciding which character to start the next line on,
2340 and what hpos to start it at.
2341 Also set `lastpos' to the last position which counts as "on this line"
2342 for cursor-positioning. */
2343
2344 if (pos < ZV)
2345 {
2346 if (FETCH_CHAR (pos) == '\n')
dd5f6267
KH
2347 {
2348 /* If stopped due to a newline, start next line after it */
2349 pos++;
2350 /* Check again for hidden lines, in case the newline occurred exactly
2351 at the right margin. */
2352 while (pos < ZV && selective > 0
2353 && indented_beyond_p (pos, selective))
2354 pos = find_next_newline (pos, 1);
2355 }
a2889657
JB
2356 else
2357 /* Stopped due to right margin of window */
2358 {
2359 if (truncate)
2360 {
278feba9 2361 *p1++ = fix_glyph (f, truncator, 0);
a2889657
JB
2362 /* Truncating => start next line after next newline,
2363 and point is on this line if it is before the newline,
2364 and skip none of first char of next line */
dd5f6267
KH
2365 do
2366 pos = find_next_newline (pos, 1);
2367 while (pos < ZV && selective > 0
2368 && indented_beyond_p (pos, selective));
a2889657
JB
2369 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
2370
2371 lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
2372 }
2373 else
2374 {
278feba9 2375 *p1++ = fix_glyph (f, continuer, 0);
a2889657
JB
2376 val.vpos = 0;
2377 lastpos--;
2378 }
2379 }
2380 }
2381
2382 /* If point is at eol or in invisible text at eol,
44fa5b1e 2383 record its frame location now. */
a2889657 2384
ae3b1442 2385 if (start <= PT && PT <= lastpos && cursor_vpos < 0)
a2889657
JB
2386 {
2387 cursor_vpos = vpos;
d2f84654 2388 cursor_hpos = p1 - leftmargin;
a2889657
JB
2389 }
2390
2391 if (cursor_vpos == vpos)
2392 {
2393 if (cursor_hpos < 0) cursor_hpos = 0;
2394 if (cursor_hpos > width) cursor_hpos = width;
2395 cursor_hpos += XFASTINT (w->left);
44fa5b1e 2396 if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
a2889657 2397 {
44fa5b1e
JB
2398 FRAME_CURSOR_Y (f) = cursor_vpos;
2399 FRAME_CURSOR_X (f) = cursor_hpos;
a2889657
JB
2400
2401 if (w == XWINDOW (selected_window))
2402 {
2403 /* Line is not continued and did not start
2404 in middle of character */
2405 if ((hpos - XFASTINT (w->left)
2406 == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
2407 && val.vpos)
2408 {
2409 this_line_bufpos = start;
2410 this_line_buffer = current_buffer;
2411 this_line_vpos = cursor_vpos;
2412 this_line_start_hpos = hpos;
2413 this_line_endpos = Z - lastpos;
2414 }
2415 else
2416 this_line_bufpos = 0;
2417 }
2418 }
2419 }
2420
2421 /* If hscroll and line not empty, insert truncation-at-left marker */
2422 if (hscroll && lastpos != start)
2423 {
d2f84654
RS
2424 *leftmargin = fix_glyph (f, truncator, 0);
2425 if (p1 <= leftmargin)
2426 p1 = leftmargin + 1;
a2889657
JB
2427 }
2428
44fa5b1e 2429 if (XFASTINT (w->width) + XFASTINT (w->left) != FRAME_WIDTH (f))
a2889657
JB
2430 {
2431 endp++;
d2f84654 2432 if (p1 < leftmargin) p1 = leftmargin;
a2889657 2433 while (p1 < endp) *p1++ = SPACEGLYPH;
b1d1124b 2434
88f22aff
JB
2435 /* Don't draw vertical bars if we're using scroll bars. They're
2436 covered up by the scroll bars, and it's distracting to see
2437 them when the scroll bar windows are flickering around to be
b1d1124b 2438 reconfigured. */
88f22aff 2439 *p1++ = (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
b1d1124b 2440 ? ' ' : '|');
a2889657
JB
2441 }
2442 desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
2443 p1 - desired_glyphs->glyphs[vpos]);
2444 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
2445
2446 /* If the start of this line is the overlay arrow-position,
2447 then put the arrow string into the display-line. */
2448
2449 if (XTYPE (Voverlay_arrow_position) == Lisp_Marker
2450 && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
2451 && start == marker_position (Voverlay_arrow_position)
2452 && XTYPE (Voverlay_arrow_string) == Lisp_String
2453 && ! overlay_arrow_seen)
2454 {
2455 unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
2456 int i;
2457 int len = XSTRING (Voverlay_arrow_string)->size;
142be3dd 2458 int arrow_end;
a2889657 2459
b1d1124b
JB
2460 if (len > width)
2461 len = width;
a2889657 2462 for (i = 0; i < len; i++)
d2f84654 2463 leftmargin[i] = p[i];
142be3dd
JB
2464
2465 /* Bug in SunOS 4.1.1 compiler requires this intermediate variable. */
d2f84654 2466 arrow_end = (leftmargin - desired_glyphs->glyphs[vpos]) + len;
142be3dd
JB
2467 if (desired_glyphs->used[vpos] < arrow_end)
2468 desired_glyphs->used[vpos] = arrow_end;
a2889657
JB
2469
2470 overlay_arrow_seen = 1;
2471 }
2472
2473 val.bufpos = pos;
2474 val_display_text_line = val;
2475 return &val_display_text_line;
2476}
2477\f
7ce2c095
RS
2478/* Redisplay the menu bar in the frame for window W. */
2479
2480static void
2481display_menu_bar (w)
2482 struct window *w;
2483{
2484 Lisp_Object items, tail;
2485 register int vpos = 0;
2486 register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2487 int maxendcol = FRAME_WIDTH (f);
2488 int hpos = 0;
8351baf2 2489 int i;
7ce2c095 2490
76412d64 2491#ifndef USE_X_TOOLKIT
7ce2c095
RS
2492 if (FRAME_MENU_BAR_LINES (f) <= 0)
2493 return;
2494
2495 get_display_line (f, vpos, 0);
2496
8351baf2
RS
2497 items = FRAME_MENU_BAR_ITEMS (f);
2498 for (i = 0; i < XVECTOR (items)->size; i += 3)
7ce2c095 2499 {
8351baf2
RS
2500 Lisp_Object pos, string;
2501 string = XVECTOR (items)->contents[i + 1];
2502 if (NILP (string))
2503 break;
2d66ad19 2504
8351baf2 2505 XFASTINT (XVECTOR (items)->contents[i + 2]) = hpos;
7ce2c095
RS
2506
2507 if (hpos < maxendcol)
2508 hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
2509 XSTRING (string)->data,
90adcf20 2510 XSTRING (string)->size,
278feba9 2511 hpos, 0, 0, hpos, maxendcol);
2d66ad19
RS
2512 /* Put a gap of 3 spaces between items. */
2513 if (hpos < maxendcol)
2514 {
2515 int hpos1 = hpos + 3;
278feba9 2516 hpos = display_string (w, vpos, "", 0, hpos, 0, 0,
2d66ad19
RS
2517 min (hpos1, maxendcol), maxendcol);
2518 }
7ce2c095
RS
2519 }
2520
2521 FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
2522 FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
2d66ad19
RS
2523
2524 /* Fill out the line with spaces. */
2525 if (maxendcol > hpos)
278feba9 2526 hpos = display_string (w, vpos, "", 0, hpos, 0, 0, maxendcol, maxendcol);
db6f348c
JB
2527
2528 /* Clear the rest of the lines allocated to the menu bar. */
2529 vpos++;
2530 while (vpos < FRAME_MENU_BAR_LINES (f))
2531 get_display_line (f, vpos++, 0);
76412d64 2532#endif /* not USE_X_TOOLKIT */
7ce2c095
RS
2533}
2534\f
a2889657
JB
2535/* Display the mode line for window w */
2536
2537static void
2538display_mode_line (w)
2539 struct window *w;
2540{
2541 register int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
2542 register int left = XFASTINT (w->left);
2543 register int right = XFASTINT (w->width) + left;
44fa5b1e 2544 register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
a2889657 2545
aa6d10fa
RS
2546 line_number_displayed = 0;
2547
44fa5b1e 2548 get_display_line (f, vpos, left);
a2889657
JB
2549 display_mode_element (w, vpos, left, 0, right, right,
2550 current_buffer->mode_line_format);
44fa5b1e 2551 FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
a2889657
JB
2552
2553 /* Make the mode line inverse video if the entire line
2554 is made of mode lines.
2555 I.e. if this window is full width,
2556 or if it is the child of a full width window
2557 (which implies that that window is split side-by-side
2558 and the rest of this line is mode lines of the sibling windows). */
44fa5b1e
JB
2559 if (XFASTINT (w->width) == FRAME_WIDTH (f)
2560 || XFASTINT (XWINDOW (w->parent)->width) == FRAME_WIDTH (f))
2561 FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
4cdc65eb 2562#ifdef HAVE_X_WINDOWS
d7eb09a0
RS
2563 else if (! FRAME_TERMCAP_P (f))
2564 {
2565 /* For a partial width window, explicitly set face of each glyph. */
2566 int i;
2567 GLYPH *ptr = FRAME_DESIRED_GLYPHS (f)->glyphs[vpos];
2568 for (i = left; i < right; ++i)
4cdc65eb 2569 ptr[i] = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (ptr[i]), 1);
d7eb09a0 2570 }
4cdc65eb 2571#endif
a2889657
JB
2572
2573#ifdef HAVE_X_WINDOWS
96a410bc
KH
2574 if (w == XWINDOW (f->selected_window))
2575 x_consider_frame_title (WINDOW_FRAME (w));
a2889657
JB
2576#endif
2577}
2578
2579/* Contribute ELT to the mode line for window W.
2580 How it translates into text depends on its data type.
2581
2582 VPOS is the position of the mode line being displayed.
2583
44fa5b1e 2584 HPOS is the position (absolute on frame) where this element's text
a2889657
JB
2585 should start. The output is truncated automatically at the right
2586 edge of window W.
2587
2588 DEPTH is the depth in recursion. It is used to prevent
2589 infinite recursion here.
2590
2591 MINENDCOL is the hpos before which the element may not end.
2592 The element is padded at the right with spaces if nec
2593 to reach this column.
2594
2595 MAXENDCOL is the hpos past which this element may not extend.
2596 If MINENDCOL is > MAXENDCOL, MINENDCOL takes priority.
2597 (This is necessary to make nested padding and truncation work.)
2598
2599 Returns the hpos of the end of the text generated by ELT.
2600 The next element will receive that value as its HPOS arg,
2601 so as to concatenate the elements. */
2602
2603static int
2604display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
2605 struct window *w;
2606 register int vpos, hpos;
2607 int depth;
2608 int minendcol;
2609 register int maxendcol;
2610 register Lisp_Object elt;
2611{
2612 tail_recurse:
2613 if (depth > 10)
2614 goto invalid;
2615
2616 depth++;
2617
2618#ifdef SWITCH_ENUM_BUG
2619 switch ((int) XTYPE (elt))
2620#else
2621 switch (XTYPE (elt))
2622#endif
2623 {
2624 case Lisp_String:
2625 {
2626 /* A string: output it and check for %-constructs within it. */
2627 register unsigned char c;
2628 register unsigned char *this = XSTRING (elt)->data;
2629
2630 while (hpos < maxendcol && *this)
2631 {
2632 unsigned char *last = this;
2633 while ((c = *this++) != '\0' && c != '%')
2634 ;
2635 if (this - 1 != last)
2636 {
2637 register int lim = --this - last + hpos;
278feba9
RS
2638 hpos = display_string (w, vpos, last, -1, hpos, 0, 1,
2639 hpos, min (lim, maxendcol));
a2889657
JB
2640 }
2641 else /* c == '%' */
2642 {
2643 register int spec_width = 0;
2644
2645 /* We can't allow -ve args due to the "%-" construct */
2646 /* Argument specifies minwidth but not maxwidth
2647 (maxwidth can be specified by
2648 (<negative-number> . <stuff>) mode-line elements) */
2649
2650 while ((c = *this++) >= '0' && c <= '9')
2651 {
2652 spec_width = spec_width * 10 + (c - '0');
2653 }
2654
2655 spec_width += hpos;
2656 if (spec_width > maxendcol)
2657 spec_width = maxendcol;
2658
2659 if (c == 'M')
2660 hpos = display_mode_element (w, vpos, hpos, depth,
2661 spec_width, maxendcol,
2662 Vglobal_mode_string);
2663 else if (c != 0)
2664 hpos = display_string (w, vpos,
2665 decode_mode_spec (w, c,
2666 maxendcol - hpos),
90adcf20 2667 -1,
278feba9 2668 hpos, 0, 1, spec_width, maxendcol);
a2889657
JB
2669 }
2670 }
2671 }
2672 break;
2673
2674 case Lisp_Symbol:
2675 /* A symbol: process the value of the symbol recursively
2676 as if it appeared here directly. Avoid error if symbol void.
2677 Special case: if value of symbol is a string, output the string
2678 literally. */
2679 {
2680 register Lisp_Object tem;
2681 tem = Fboundp (elt);
265a9e55 2682 if (!NILP (tem))
a2889657
JB
2683 {
2684 tem = Fsymbol_value (elt);
2685 /* If value is a string, output that string literally:
2686 don't check for % within it. */
2687 if (XTYPE (tem) == Lisp_String)
2688 hpos = display_string (w, vpos, XSTRING (tem)->data,
90adcf20 2689 XSTRING (tem)->size,
278feba9 2690 hpos, 0, 1, minendcol, maxendcol);
a2889657
JB
2691 /* Give up right away for nil or t. */
2692 else if (!EQ (tem, elt))
2693 { elt = tem; goto tail_recurse; }
2694 }
2695 }
2696 break;
2697
2698 case Lisp_Cons:
2699 {
2700 register Lisp_Object car, tem;
2701
2702 /* A cons cell: three distinct cases.
2703 If first element is a string or a cons, process all the elements
2704 and effectively concatenate them.
2705 If first element is a negative number, truncate displaying cdr to
2706 at most that many characters. If positive, pad (with spaces)
2707 to at least that many characters.
2708 If first element is a symbol, process the cadr or caddr recursively
2709 according to whether the symbol's value is non-nil or nil. */
2710 car = XCONS (elt)->car;
2711 if (XTYPE (car) == Lisp_Symbol)
2712 {
2713 tem = Fboundp (car);
2714 elt = XCONS (elt)->cdr;
2715 if (XTYPE (elt) != Lisp_Cons)
2716 goto invalid;
2717 /* elt is now the cdr, and we know it is a cons cell.
2718 Use its car if CAR has a non-nil value. */
265a9e55 2719 if (!NILP (tem))
a2889657
JB
2720 {
2721 tem = Fsymbol_value (car);
265a9e55 2722 if (!NILP (tem))
a2889657
JB
2723 { elt = XCONS (elt)->car; goto tail_recurse; }
2724 }
2725 /* Symbol's value is nil (or symbol is unbound)
2726 Get the cddr of the original list
2727 and if possible find the caddr and use that. */
2728 elt = XCONS (elt)->cdr;
265a9e55 2729 if (NILP (elt))
a2889657
JB
2730 break;
2731 else if (XTYPE (elt) != Lisp_Cons)
2732 goto invalid;
2733 elt = XCONS (elt)->car;
2734 goto tail_recurse;
2735 }
2736 else if (XTYPE (car) == Lisp_Int)
2737 {
2738 register int lim = XINT (car);
2739 elt = XCONS (elt)->cdr;
2740 if (lim < 0)
2741 /* Negative int means reduce maximum width.
2742 DO NOT change MINENDCOL here!
2743 (20 -10 . foo) should truncate foo to 10 col
2744 and then pad to 20. */
2745 maxendcol = min (maxendcol, hpos - lim);
2746 else if (lim > 0)
2747 {
2748 /* Padding specified. Don't let it be more than
2749 current maximum. */
2750 lim += hpos;
2751 if (lim > maxendcol)
2752 lim = maxendcol;
2753 /* If that's more padding than already wanted, queue it.
2754 But don't reduce padding already specified even if
2755 that is beyond the current truncation point. */
2756 if (lim > minendcol)
2757 minendcol = lim;
2758 }
2759 goto tail_recurse;
2760 }
2761 else if (XTYPE (car) == Lisp_String || XTYPE (car) == Lisp_Cons)
2762 {
2763 register int limit = 50;
2764 /* LIMIT is to protect against circular lists. */
2765 while (XTYPE (elt) == Lisp_Cons && --limit > 0
2766 && hpos < maxendcol)
2767 {
2768 hpos = display_mode_element (w, vpos, hpos, depth,
2769 hpos, maxendcol,
2770 XCONS (elt)->car);
2771 elt = XCONS (elt)->cdr;
2772 }
2773 }
2774 }
2775 break;
2776
2777 default:
2778 invalid:
278feba9 2779 return (display_string (w, vpos, "*invalid*", -1, hpos, 0, 1,
a2889657
JB
2780 minendcol, maxendcol));
2781 }
2782
2783 end:
2784 if (minendcol > hpos)
278feba9 2785 hpos = display_string (w, vpos, "", 0, hpos, 0, 1, minendcol, maxendcol);
a2889657
JB
2786 return hpos;
2787}
2788\f
2789/* Return a string for the output of a mode line %-spec for window W,
2790 generated by character C and width MAXWIDTH. */
2791
11e82b76
JB
2792static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
2793
a2889657
JB
2794static char *
2795decode_mode_spec (w, c, maxwidth)
2796 struct window *w;
2797 register char c;
2798 register int maxwidth;
2799{
0b67772d 2800 Lisp_Object obj;
44fa5b1e
JB
2801 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2802 char *decode_mode_spec_buf = (char *) FRAME_TEMP_GLYPHS (f)->total_contents;
a2889657 2803
0b67772d 2804 obj = Qnil;
44fa5b1e
JB
2805 if (maxwidth > FRAME_WIDTH (f))
2806 maxwidth = FRAME_WIDTH (f);
a2889657
JB
2807
2808 switch (c)
2809 {
2810 case 'b':
2811 obj = current_buffer->name;
2812#if 0
2813 if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
2814 {
2815 bcopy (XSTRING (obj)->data, decode_mode_spec_buf, maxwidth - 1);
2816 decode_mode_spec_buf[maxwidth - 1] = '\\';
2817 decode_mode_spec_buf[maxwidth] = '\0';
2818 return decode_mode_spec_buf;
2819 }
2820#endif
2821 break;
2822
2823 case 'f':
2824 obj = current_buffer->filename;
2825#if 0
265a9e55 2826 if (NILP (obj))
a2889657
JB
2827 return "[none]";
2828 else if (XTYPE (obj) == Lisp_String && XSTRING (obj)->size > maxwidth)
2829 {
2830 bcopy ("...", decode_mode_spec_buf, 3);
2831 bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
2832 decode_mode_spec_buf + 3, maxwidth - 3);
2833 return decode_mode_spec_buf;
2834 }
2835#endif
2836 break;
2837
aa6d10fa
RS
2838 case 'l':
2839 {
2840 int startpos = marker_position (w->start);
2841 int line, linepos, topline;
2842 int nlines, junk;
2843 Lisp_Object tem;
2844 int height = XFASTINT (w->height);
2845
2846 /* If we decided that this buffer isn't suitable for line numbers,
2847 don't forget that too fast. */
2848 if (EQ (w->base_line_pos, w->buffer))
2849 return "??";
2850
2851 /* If the buffer is very big, don't waste time. */
2852 if (ZV - BEGV > line_number_display_limit)
2853 {
2854 w->base_line_pos = Qnil;
2855 w->base_line_number = Qnil;
2856 return "??";
2857 }
2858
2859 if (!NILP (w->base_line_number)
2860 && !NILP (w->base_line_pos)
2861 && XFASTINT (w->base_line_pos) <= marker_position (w->start))
2862 {
2863 line = XFASTINT (w->base_line_number);
2864 linepos = XFASTINT (w->base_line_pos);
2865 }
2866 else
2867 {
2868 line = 1;
2869 linepos = BEGV;
2870 }
2871
2872 /* Count lines from base line to window start position. */
2873 nlines = display_count_lines (linepos, startpos, startpos, &junk);
2874
2875 topline = nlines + line;
2876
2877 /* Determine a new base line, if the old one is too close
2878 or too far away, or if we did not have one.
2879 "Too close" means it's plausible a scroll-down would
2880 go back past it. */
2881 if (startpos == BEGV)
2882 {
2883 XFASTINT (w->base_line_number) = topline;
2884 XFASTINT (w->base_line_pos) = BEGV;
2885 }
2886 else if (nlines < height + 25 || nlines > height * 3 + 50
2887 || linepos == BEGV)
2888 {
2889 int limit = BEGV;
2890 int position;
2891 int distance = (height * 2 + 30) * 200;
2892
2893 if (startpos - distance > limit)
2894 limit = startpos - distance;
2895
2896 nlines = display_count_lines (startpos, limit,
2897 -(height * 2 + 30),
2898 &position);
2899 /* If we couldn't find the lines we wanted within
2900 200 chars per line,
2901 give up on line numbers for this window. */
2902 if (position == startpos - distance)
2903 {
2904 w->base_line_pos = w->buffer;
2905 w->base_line_number = Qnil;
2906 return "??";
2907 }
2908
2909 XFASTINT (w->base_line_number) = topline - nlines;
2910 XFASTINT (w->base_line_pos) = position;
2911 }
2912
2913 /* Now count lines from the start pos to point. */
2914 nlines = display_count_lines (startpos, PT, PT, &junk);
2915
2916 /* Record that we did display the line number. */
2917 line_number_displayed = 1;
2918
2919 /* Make the string to show. */
2920 sprintf (decode_mode_spec_buf, "%d", topline + nlines);
2921 return decode_mode_spec_buf;
2922 }
2923 break;
2924
a2889657
JB
2925 case 'm':
2926 obj = current_buffer->mode_name;
2927 break;
2928
2929 case 'n':
2930 if (BEGV > BEG || ZV < Z)
2931 return " Narrow";
2932 break;
2933
2934 case '*':
265a9e55 2935 if (!NILP (current_buffer->read_only))
a2889657
JB
2936 return "%";
2937 if (MODIFF > current_buffer->save_modified)
2938 return "*";
2939 return "-";
2940
5cc9f80d
RS
2941 case '+':
2942 if (MODIFF > current_buffer->save_modified)
2943 return "*";
2944 return "-";
2945
a2889657
JB
2946 case 's':
2947 /* status of process */
a2889657 2948 obj = Fget_buffer_process (Fcurrent_buffer ());
265a9e55 2949 if (NILP (obj))
a2889657 2950 return "no process";
76412d64 2951#ifdef subprocesses
a2889657 2952 obj = Fsymbol_name (Fprocess_status (obj));
76412d64 2953#endif
a2889657 2954 break;
a2889657 2955
76412d64
RS
2956 case 't': /* indicate TEXT or BINARY */
2957#ifdef MSDOS
6b4b5267 2958 return NILP (current_buffer->buffer_file_type) ? "T" : "B";
76412d64
RS
2959#else /* not MSDOS */
2960 return "T";
2961#endif /* not MSDOS */
2962
a2889657
JB
2963 case 'p':
2964 {
2965 int pos = marker_position (w->start);
2966 int total = ZV - BEGV;
2967
2968 if (XFASTINT (w->window_end_pos) <= Z - ZV)
2969 {
2970 if (pos <= BEGV)
2971 return "All";
2972 else
2973 return "Bottom";
2974 }
2975 else if (pos <= BEGV)
2976 return "Top";
2977 else
2978 {
2979 total = ((pos - BEGV) * 100 + total - 1) / total;
2980 /* We can't normally display a 3-digit number,
2981 so get us a 2-digit number that is close. */
2982 if (total == 100)
2983 total = 99;
2984 sprintf (decode_mode_spec_buf, "%2d%%", total);
2985 return decode_mode_spec_buf;
2986 }
2987 }
2988
8ffcb79f
RS
2989 /* Display percentage of size above the bottom of the screen. */
2990 case 'P':
2991 {
2992 int toppos = marker_position (w->start);
2993 int botpos = Z - XFASTINT (w->window_end_pos);
2994 int total = ZV - BEGV;
2995
2996 if (botpos >= ZV)
2997 {
2998 if (toppos <= BEGV)
2999 return "All";
3000 else
3001 return "Bottom";
3002 }
3003 else
3004 {
3005 total = ((botpos - BEGV) * 100 + total - 1) / total;
3006 /* We can't normally display a 3-digit number,
3007 so get us a 2-digit number that is close. */
3008 if (total == 100)
3009 total = 99;
3010 if (toppos <= BEGV)
3011 sprintf (decode_mode_spec_buf, "Top%2d%%", total);
3012 else
3013 sprintf (decode_mode_spec_buf, "%2d%%", total);
3014 return decode_mode_spec_buf;
3015 }
3016 }
3017
a2889657
JB
3018 case '%':
3019 return "%";
3020
3021 case '[':
3022 {
3023 int i;
3024 char *p;
3025
3026 if (command_loop_level > 5)
3027 return "[[[... ";
3028 p = decode_mode_spec_buf;
3029 for (i = 0; i < command_loop_level; i++)
3030 *p++ = '[';
3031 *p = 0;
3032 return decode_mode_spec_buf;
3033 }
3034
3035 case ']':
3036 {
3037 int i;
3038 char *p;
3039
3040 if (command_loop_level > 5)
3041 return " ...]]]";
3042 p = decode_mode_spec_buf;
3043 for (i = 0; i < command_loop_level; i++)
3044 *p++ = ']';
3045 *p = 0;
3046 return decode_mode_spec_buf;
3047 }
3048
3049 case '-':
3050 {
a2889657
JB
3051 register char *p;
3052 register int i;
3053
3054 if (maxwidth < sizeof (lots_of_dashes))
3055 return lots_of_dashes;
3056 else
3057 {
3058 for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
3059 *p++ = '-';
3060 *p = '\0';
3061 }
3062 return decode_mode_spec_buf;
3063 }
3064 }
3065
3066 if (XTYPE (obj) == Lisp_String)
3067 return (char *) XSTRING (obj)->data;
3068 else
3069 return "";
3070}
aa6d10fa
RS
3071
3072/* Count up to N lines starting from FROM.
3073 But don't go beyond LIMIT.
3074 Return the number of lines thus found (always positive).
3075 Store the position after what was found into *POS_PTR. */
3076
3077static int
3078display_count_lines (from, limit, n, pos_ptr)
3079 int from, limit, n;
3080 int *pos_ptr;
3081{
3082 int oldbegv = BEGV;
3083 int oldzv = ZV;
3084 int shortage = 0;
3085
3086 if (limit < from)
3087 BEGV = limit;
3088 else
3089 ZV = limit;
3090
278feba9 3091 *pos_ptr = scan_buffer ('\n', from, n, &shortage, 0);
aa6d10fa
RS
3092
3093 ZV = oldzv;
3094 BEGV = oldbegv;
3095
3096 if (n < 0)
3097 /* When scanning backwards, scan_buffer stops *after* the last newline
3098 it finds, but does count it. Compensate for that. */
3099 return - n - shortage - (*pos_ptr != limit);
3100 return n - shortage;
3101}
a2889657
JB
3102\f
3103/* Display STRING on one line of window W, starting at HPOS.
3104 Display at position VPOS. Caller should have done get_display_line.
11e82b76 3105 If VPOS == -1, display it as the current frame's title.
90adcf20 3106 LENGTH is the length of STRING, or -1 meaning STRING is null-terminated.
a2889657
JB
3107
3108 TRUNCATE is GLYPH to display at end if truncated. Zero for none.
3109
3110 MINCOL is the first column ok to end at. (Pad with spaces to this col.)
3111 MAXCOL is the last column ok to end at. Truncate here.
3112 -1 for MINCOL or MAXCOL means no explicit minimum or maximum.
44fa5b1e 3113 Both count from the left edge of the frame, as does HPOS.
a2889657
JB
3114 The right edge of W is an implicit maximum.
3115 If TRUNCATE is nonzero, the implicit maximum is one column before the edge.
3116
278feba9
RS
3117 OBEY_WINDOW_WIDTH says to put spaces or vertical bars
3118 at the place where the current window ends in this line
3119 and not display anything beyond there. Otherwise, only MAXCOL
3120 controls where to stop output.
3121
3122 Returns ending hpos. */
a2889657
JB
3123
3124static int
278feba9
RS
3125display_string (w, vpos, string, length, hpos, truncate,
3126 obey_window_width, mincol, maxcol)
a2889657
JB
3127 struct window *w;
3128 unsigned char *string;
90adcf20 3129 int length;
a2889657
JB
3130 int vpos, hpos;
3131 GLYPH truncate;
278feba9 3132 int obey_window_width;
a2889657
JB
3133 int mincol, maxcol;
3134{
3135 register int c;
3136 register GLYPH *p1;
3137 int hscroll = XINT (w->hscroll);
253c7d2f 3138 int tab_width = XINT (XBUFFER (w->buffer)->tab_width);
a2889657
JB
3139 register GLYPH *start;
3140 register GLYPH *end;
b1d1124b
JB
3141 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
3142 struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
a2889657
JB
3143 GLYPH *p1start = desired_glyphs->glyphs[vpos] + hpos;
3144 int window_width = XFASTINT (w->width);
3145
3146 /* Use the standard display table, not the window's display table.
3147 We don't want the mode line in rot13. */
3148 register struct Lisp_Vector *dp = 0;
efc63ef0 3149 int i;
a2889657
JB
3150
3151 if (XTYPE (Vstandard_display_table) == Lisp_Vector
3152 && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
3153 dp = XVECTOR (Vstandard_display_table);
3154
54ff581a 3155 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
a2889657
JB
3156
3157 p1 = p1start;
3158 start = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
a2889657 3159
278feba9 3160 if (obey_window_width)
b1d1124b 3161 {
278feba9
RS
3162 end = start + window_width - (truncate != 0);
3163
3164 if ((window_width + XFASTINT (w->left)) != FRAME_WIDTH (f))
b1d1124b 3165 {
278feba9
RS
3166 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
3167 {
3168 int i;
b1d1124b 3169
278feba9
RS
3170 for (i = 0; i < VERTICAL_SCROLL_BAR_WIDTH; i++)
3171 *end-- = ' ';
3172 }
3173 else
3174 *end-- = '|';
b1d1124b 3175 }
b1d1124b 3176 }
a2889657 3177
278feba9
RS
3178 if (! obey_window_width
3179 || (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol))
a2889657 3180 end = desired_glyphs->glyphs[vpos] + maxcol;
278feba9 3181
efc63ef0 3182 /* Store 0 in charstart for these columns. */
bd5dec8e 3183 for (i = (hpos >= 0 ? hpos : 0); i < end - p1start + hpos; i++)
efc63ef0
RS
3184 desired_glyphs->charstarts[vpos][i] = 0;
3185
a2889657
JB
3186 if (maxcol >= 0 && mincol > maxcol)
3187 mincol = maxcol;
3188
3189 while (p1 < end)
3190 {
90adcf20
RS
3191 if (length == 0)
3192 break;
a2889657 3193 c = *string++;
90adcf20
RS
3194 /* Specified length. */
3195 if (length >= 0)
3196 length--;
3197 /* Unspecified length (null-terminated string). */
3198 else if (c == 0)
3199 break;
3200
a2889657 3201 if (c >= 040 && c < 0177
c581d710 3202 && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
a2889657
JB
3203 {
3204 if (p1 >= start)
3205 *p1 = c;
3206 p1++;
3207 }
3208 else if (c == '\t')
3209 {
3210 do
3211 {
3212 if (p1 >= start && p1 < end)
3213 *p1 = SPACEGLYPH;
3214 p1++;
3215 }
3216 while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
3217 }
c581d710 3218 else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
278feba9
RS
3219 {
3220 p1 = copy_part_of_rope (f, p1, start,
3221 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
3222 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
3223 0);
3224 }
ded34426 3225 else if (c < 0200 && ! NILP (buffer_defaults.ctl_arrow))
a2889657
JB
3226 {
3227 if (p1 >= start)
278feba9
RS
3228 *p1 = fix_glyph (f, (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
3229 ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
3230 0);
a2889657 3231 p1++;
6e8290aa 3232 if (p1 >= start && p1 < end)
a2889657
JB
3233 *p1 = c ^ 0100;
3234 p1++;
3235 }
3236 else
3237 {
3238 if (p1 >= start)
278feba9
RS
3239 *p1 = fix_glyph (f, (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
3240 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
3241 0);
a2889657 3242 p1++;
6e8290aa 3243 if (p1 >= start && p1 < end)
a2889657
JB
3244 *p1 = (c >> 6) + '0';
3245 p1++;
6e8290aa 3246 if (p1 >= start && p1 < end)
a2889657
JB
3247 *p1 = (7 & (c >> 3)) + '0';
3248 p1++;
6e8290aa 3249 if (p1 >= start && p1 < end)
a2889657
JB
3250 *p1 = (7 & c) + '0';
3251 p1++;
3252 }
3253 }
3254
90adcf20 3255 if (c && length > 0)
a2889657
JB
3256 {
3257 p1 = end;
278feba9 3258 if (truncate) *p1++ = fix_glyph (f, truncate, 0);
a2889657
JB
3259 }
3260 else if (mincol >= 0)
3261 {
3262 end = desired_glyphs->glyphs[vpos] + mincol;
3263 while (p1 < end)
3264 *p1++ = SPACEGLYPH;
3265 }
3266
3267 {
3268 register int len = p1 - desired_glyphs->glyphs[vpos];
3269
3270 if (len > desired_glyphs->used[vpos])
3271 desired_glyphs->used[vpos] = len;
3272 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
3273
3274 return len;
3275 }
3276}
3277\f
3278void
3279syms_of_xdisp ()
3280{
cf074754
RS
3281 staticpro (&Qmenu_bar_update_hook);
3282 Qmenu_bar_update_hook = intern ("menu-bar-update-hook");
3283
a2889657
JB
3284 staticpro (&last_arrow_position);
3285 staticpro (&last_arrow_string);
3286 last_arrow_position = Qnil;
3287 last_arrow_string = Qnil;
3288
3289 DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
8c45d522 3290 "String (or mode line construct) included (normally) in `mode-line-format'.");
a2889657
JB
3291 Vglobal_mode_string = Qnil;
3292
3293 DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
3294 "Marker for where to display an arrow on top of the buffer text.\n\
3295This must be the beginning of a line in order to work.\n\
3296See also `overlay-arrow-string'.");
3297 Voverlay_arrow_position = Qnil;
3298
3299 DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
3300 "String to display as an arrow. See also `overlay-arrow-position'.");
3301 Voverlay_arrow_string = Qnil;
3302
3303 DEFVAR_INT ("scroll-step", &scroll_step,
3304 "*The number of lines to try scrolling a window by when point moves out.\n\
44fa5b1e
JB
3305If that fails to bring point back on frame, point is centered instead.\n\
3306If this is zero, point is always centered after it moves off frame.");
a2889657
JB
3307
3308 DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
3309
3310 DEFVAR_BOOL ("truncate-partial-width-windows",
3311 &truncate_partial_width_windows,
44fa5b1e 3312 "*Non-nil means truncate lines in all windows less than full frame wide.");
a2889657
JB
3313 truncate_partial_width_windows = 1;
3314
3315 DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
3316 "*Non-nil means use inverse video for the mode line.");
3317 mode_line_inverse_video = 1;
aa6d10fa
RS
3318
3319 DEFVAR_INT ("line-number-display-limit", &line_number_display_limit,
3320 "*Maximum buffer size for which line number should be displayed.");
3321 line_number_display_limit = 1000000;
fba9ce76
RS
3322
3323 DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
3324 "*Non-nil means highlight region even in nonselected windows.");
3325 highlight_nonselected_windows = 1;
a2889657
JB
3326}
3327
3328/* initialize the window system */
3329init_xdisp ()
3330{
3331 Lisp_Object root_window;
3332#ifndef COMPILER_REGISTER_BUG
3333 register
3334#endif /* COMPILER_REGISTER_BUG */
3335 struct window *mini_w;
3336
3337 this_line_bufpos = 0;
3338
3339 mini_w = XWINDOW (minibuf_window);
11e82b76 3340 root_window = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (mini_w)));
a2889657
JB
3341
3342 echo_area_glyphs = 0;
3343 previous_echo_glyphs = 0;
3344
3345 if (!noninteractive)
3346 {
44fa5b1e 3347 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (root_window)));
a2889657 3348 XFASTINT (XWINDOW (root_window)->top) = 0;
44fa5b1e
JB
3349 set_window_height (root_window, FRAME_HEIGHT (f) - 1, 0);
3350 XFASTINT (mini_w->top) = FRAME_HEIGHT (f) - 1;
a2889657
JB
3351 set_window_height (minibuf_window, 1, 0);
3352
44fa5b1e
JB
3353 XFASTINT (XWINDOW (root_window)->width) = FRAME_WIDTH (f);
3354 XFASTINT (mini_w->width) = FRAME_WIDTH (f);
a2889657
JB
3355 }
3356}