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