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