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