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