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