(Fset_window_redisplay_end_trigger): Doc fix.
[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
d3413a53
RS
1287 if (FRAME_X_P (f)
1288 ?
dc937613 1289#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
cf074754 1290 FRAME_EXTERNAL_MENU_BAR (f)
78614721 1291#else
cf074754 1292 FRAME_MENU_BAR_LINES (f) > 0
78614721 1293#endif
d3413a53 1294 : FRAME_MENU_BAR_LINES (f) > 0)
90adcf20
RS
1295 {
1296 /* If the user has switched buffers or windows, we need to
1297 recompute to reflect the new bindings. But we'll
1298 recompute when update_mode_lines is set too; that means
1299 that people can use force-mode-line-update to request
1300 that the menu bar be recomputed. The adverse effect on
1301 the rest of the redisplay algorithm is about the same as
1302 windows_or_buffers_changed anyway. */
1303 if (windows_or_buffers_changed
cf074754 1304 || !NILP (w->update_mode_line)
90adcf20
RS
1305 || (XFASTINT (w->last_modified) < MODIFF
1306 && (XFASTINT (w->last_modified)
94bb7f9b
KH
1307 <= BUF_SAVE_MODIFF (XBUFFER (w->buffer))))
1308 || ((!NILP (Vtransient_mark_mode)
1309 && !NILP (XBUFFER (w->buffer)->mark_active))
1310 != !NILP (w->region_showing)))
90adcf20
RS
1311 {
1312 struct buffer *prev = current_buffer;
a2725ab2
RS
1313 int count = specpdl_ptr - specpdl;
1314
399164b4 1315 set_buffer_internal_1 (XBUFFER (w->buffer));
eac4251c 1316 if (save_match_data)
a2725ab2 1317 record_unwind_protect (Fstore_match_data, Fmatch_data ());
399164b4 1318 if (NILP (Voverriding_local_map_menu_flag))
d46fb96a
KH
1319 {
1320 specbind (Qoverriding_terminal_local_map, Qnil);
1321 specbind (Qoverriding_local_map, Qnil);
1322 }
a2725ab2 1323
34acc8e6
KH
1324 /* Run the Lucid hook. */
1325 call1 (Vrun_hooks, Qactivate_menubar_hook);
1326 /* If it has changed current-menubar from previous value,
1327 really recompute the menubar from the value. */
1328 if (! NILP (Vlucid_menu_bar_dirty_flag))
1329 call0 (Qrecompute_lucid_menubar);
cf074754 1330 call1 (Vrun_hooks, Qmenu_bar_update_hook);
8351baf2 1331 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
8f3343d0 1332#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
d3413a53
RS
1333 if (FRAME_X_P (f))
1334 set_frame_menubar (f, 0, 0);
8f3343d0 1335#endif /* USE_X_TOOLKIT || HAVE_NTGUI */
a2725ab2
RS
1336
1337 unbind_to (count, Qnil);
399164b4 1338 set_buffer_internal_1 (prev);
90adcf20
RS
1339 }
1340 }
1341}
1342\f
a2889657
JB
1343int do_id = 1;
1344
90adcf20
RS
1345/* Redisplay WINDOW and its subwindows and siblings. */
1346
a2889657
JB
1347static void
1348redisplay_windows (window)
1349 Lisp_Object window;
1350{
265a9e55 1351 for (; !NILP (window); window = XWINDOW (window)->next)
a2889657
JB
1352 redisplay_window (window, 0);
1353}
1354
90adcf20
RS
1355/* Redisplay window WINDOW and its subwindows. */
1356
a2889657
JB
1357static void
1358redisplay_window (window, just_this_one)
1359 Lisp_Object window;
1360 int just_this_one;
1361{
1362 register struct window *w = XWINDOW (window);
30c566e4 1363 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
a2889657 1364 int height;
ae3b1442 1365 register int lpoint = PT;
a2889657 1366 struct buffer *old = current_buffer;
b1d1124b 1367 register int width = window_internal_width (w) - 1;
a2889657
JB
1368 register int startp;
1369 register int hscroll = XINT (w->hscroll);
1370 struct position pos;
ae3b1442 1371 int opoint = PT;
a2889657 1372 int tem;
e481f960 1373 int update_mode_line;
f908610f 1374 struct Lisp_Char_Table *dp = window_display_table (w);
a2889657 1375
44fa5b1e 1376 if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
a2889657
JB
1377
1378 /* If this is a combination window, do its children; that's all. */
1379
265a9e55 1380 if (!NILP (w->vchild))
a2889657
JB
1381 {
1382 redisplay_windows (w->vchild);
1383 return;
1384 }
265a9e55 1385 if (!NILP (w->hchild))
a2889657
JB
1386 {
1387 redisplay_windows (w->hchild);
1388 return;
1389 }
265a9e55 1390 if (NILP (w->buffer))
a2889657 1391 abort ();
8de2d90b
JB
1392
1393 height = window_internal_height (w);
4d641a15 1394 update_mode_line = (!NILP (w->update_mode_line) || update_mode_lines);
73af359d
RS
1395 if (XBUFFER (w->buffer)->clip_changed)
1396 update_mode_line = 1;
8de2d90b
JB
1397
1398 if (MINI_WINDOW_P (w))
1399 {
73af359d
RS
1400 if (w == XWINDOW (echo_area_window) && echo_area_glyphs)
1401 /* We've already displayed the echo area glyphs in this window. */
1402 goto finish_scroll_bars;
1403 else if (w != XWINDOW (minibuf_window))
8de2d90b 1404 {
73af359d
RS
1405 /* This is a minibuffer, but it's not the currently active one,
1406 so clear it. */
1407 int vpos = XFASTINT (w->top);
8de2d90b
JB
1408 int i;
1409
1410 for (i = 0; i < height; i++)
1411 {
44fa5b1e 1412 get_display_line (f, vpos + i, 0);
278feba9 1413 display_string (w, vpos + i, "", 0, 0, 0, 1, 0, width);
8de2d90b
JB
1414 }
1415
88f22aff 1416 goto finish_scroll_bars;
8de2d90b
JB
1417 }
1418 }
a2889657 1419
a2889657
JB
1420 /* Otherwise set up data on this window; select its buffer and point value */
1421
e481f960 1422 if (update_mode_line)
f72df6ac 1423 set_buffer_internal_1 (XBUFFER (w->buffer));
e481f960
RS
1424 else
1425 set_buffer_temp (XBUFFER (w->buffer));
1426
ae3b1442 1427 opoint = PT;
a2889657 1428
28995e67
RS
1429 /* If %c is in mode line, update it if needed. */
1430 if (!NILP (w->column_number_displayed)
1431 /* This alternative quickly identifies a common case
1432 where no change is needed. */
1433 && !(PT == XFASTINT (w->last_point)
1434 && XFASTINT (w->last_modified) >= MODIFF)
1435 && XFASTINT (w->column_number_displayed) != current_column ())
1436 update_mode_line = 1;
1437
42640f83
RS
1438 /* Count number of windows showing the selected buffer.
1439 An indirect buffer counts as its base buffer. */
a2889657 1440
42640f83
RS
1441 if (!just_this_one)
1442 {
1443 struct buffer *current_base, *window_base;
1444 current_base = current_buffer;
1445 window_base = XBUFFER (XWINDOW (selected_window)->buffer);
1446 if (current_base->base_buffer)
1447 current_base = current_base->base_buffer;
1448 if (window_base->base_buffer)
1449 window_base = window_base->base_buffer;
1450 if (current_base == window_base)
1451 buffer_shared++;
1452 }
a2889657
JB
1453
1454 /* POINT refers normally to the selected window.
1455 For any other window, set up appropriate value. */
1456
1457 if (!EQ (window, selected_window))
1458 {
f67a0f51
RS
1459 int new_pt = marker_position (w->pointm);
1460 if (new_pt < BEGV)
a2889657 1461 {
f67a0f51
RS
1462 new_pt = BEGV;
1463 Fset_marker (w->pointm, make_number (new_pt), Qnil);
a2889657 1464 }
f67a0f51 1465 else if (new_pt > (ZV - 1))
a2889657 1466 {
f67a0f51
RS
1467 new_pt = ZV;
1468 Fset_marker (w->pointm, make_number (new_pt), Qnil);
a2889657 1469 }
f67a0f51
RS
1470 /* We don't use SET_PT so that the point-motion hooks don't run. */
1471 BUF_PT (current_buffer) = new_pt;
a2889657
JB
1472 }
1473
f4faa47c
JB
1474 /* If any of the character widths specified in the display table
1475 have changed, invalidate the width run cache. It's true that this
1476 may be a bit late to catch such changes, but the rest of
1477 redisplay goes (non-fatally) haywire when the display table is
1478 changed, so why should we worry about doing any better? */
1479 if (current_buffer->width_run_cache)
1480 {
f908610f 1481 struct Lisp_Char_Table *disptab = buffer_display_table ();
f4faa47c
JB
1482
1483 if (! disptab_matches_widthtab (disptab,
1484 XVECTOR (current_buffer->width_table)))
1485 {
1486 invalidate_region_cache (current_buffer,
1487 current_buffer->width_run_cache,
1488 BEG, Z);
1489 recompute_width_table (current_buffer, disptab);
1490 }
1491 }
1492
a2889657 1493 /* If window-start is screwed up, choose a new one. */
a2889657
JB
1494 if (XMARKER (w->start)->buffer != current_buffer)
1495 goto recenter;
1496
1497 startp = marker_position (w->start);
1498
8de2d90b 1499 /* Handle case where place to start displaying has been specified,
aa6d10fa 1500 unless the specified location is outside the accessible range. */
265a9e55 1501 if (!NILP (w->force_start))
a2889657 1502 {
aa6d10fa
RS
1503 /* Forget any recorded base line for line number display. */
1504 w->base_line_number = Qnil;
75c43375
RS
1505 /* Redisplay the mode line. Select the buffer properly for that.
1506 Also, run the hook window-scroll-functions
1507 because we have scrolled. */
1508 if (!update_mode_line
1509 || ! NILP (Vwindow_scroll_functions))
e481f960 1510 {
75c43375
RS
1511 Lisp_Object temp[3];
1512
e481f960 1513 set_buffer_temp (old);
f72df6ac 1514 set_buffer_internal_1 (XBUFFER (w->buffer));
e481f960
RS
1515 update_mode_line = 1;
1516 w->update_mode_line = Qt;
75c43375
RS
1517 if (! NILP (Vwindow_scroll_functions))
1518 run_hook_with_args_2 (Qwindow_scroll_functions, window,
1519 make_number (startp));
e481f960 1520 }
a2889657 1521 w->force_start = Qnil;
c2213350 1522 XSETFASTINT (w->last_modified, 0);
8de2d90b
JB
1523 if (startp < BEGV) startp = BEGV;
1524 if (startp > ZV) startp = ZV;
a2889657
JB
1525 try_window (window, startp);
1526 if (cursor_vpos < 0)
1527 {
1528 /* If point does not appear, move point so it does appear */
1529 pos = *compute_motion (startp, 0,
ca26e1c8
KH
1530 (((EQ (window, minibuf_window)
1531 && startp == BEG)
1532 ? minibuf_prompt_width : 0)
1533 + (hscroll ? 1 - hscroll : 0)),
1534 0,
1535 ZV, height / 2,
68be917d 1536 - (1 << (BITS_PER_SHORT - 1)),
ca26e1c8 1537 width, hscroll, pos_tab_offset (w, startp), w);
f67a0f51 1538 BUF_PT (current_buffer) = pos.bufpos;
90adcf20 1539 if (w != XWINDOW (selected_window))
ae3b1442 1540 Fset_marker (w->pointm, make_number (PT), Qnil);
a2889657
JB
1541 else
1542 {
9d6a6bb9 1543 if (current_buffer == old)
ae3b1442 1544 lpoint = PT;
210e752f
KH
1545 FRAME_CURSOR_X (f) = (XFASTINT (w->left)
1546 + minmax (0, pos.hpos, width));
44fa5b1e 1547 FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
a2889657 1548 }
df0b5ea1
RS
1549 /* If we are highlighting the region,
1550 then we just changed the region, so redisplay to show it. */
df0b5ea1
RS
1551 if (!NILP (Vtransient_mark_mode)
1552 && !NILP (current_buffer->mark_active))
6f27fa9b
RS
1553 {
1554 cancel_my_columns (XWINDOW (window));
1555 try_window (window, startp);
1556 }
a2889657
JB
1557 }
1558 goto done;
1559 }
1560
1561 /* Handle case where text has not changed, only point,
44fa5b1e 1562 and it has not moved off the frame */
a2889657
JB
1563
1564 /* This code is not used for minibuffer for the sake of
1565 the case of redisplaying to replace an echo area message;
1566 since in that case the minibuffer contents per se are usually unchanged.
1567 This code is of no real use in the minibuffer since
1568 the handling of this_line_bufpos, etc.,
1569 in redisplay handles the same cases. */
1570
1571 if (XFASTINT (w->last_modified) >= MODIFF
86bee31c 1572 && PT >= startp && !current_buffer->clip_changed
44fa5b1e 1573 && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
b1aa6cb3
RS
1574 /* If force-mode-line-update was called, really redisplay;
1575 that's how redisplay is forced after e.g. changing
1576 buffer-invisibility-spec. */
632ab665 1577 && NILP (w->update_mode_line)
bd66d1ba
RS
1578 /* Can't use this case if highlighting a region. */
1579 && !(!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
1580 && NILP (w->region_showing)
15495c73
KH
1581 /* If end pos is out of date, scroll bar and percentage will be wrong */
1582 && INTEGERP (w->window_end_vpos)
1583 && XFASTINT (w->window_end_vpos) < XFASTINT (w->height)
a2889657
JB
1584 && !EQ (window, minibuf_window))
1585 {
ca26e1c8 1586 pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), 0,
632ab665 1587 PT, height, 0, width, hscroll,
e37f06d7 1588 pos_tab_offset (w, startp), w);
a2889657
JB
1589
1590 if (pos.vpos < height)
1591 {
44fa5b1e
JB
1592 /* Ok, point is still on frame */
1593 if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
a2889657
JB
1594 {
1595 /* These variables are supposed to be origin 1 */
210e752f
KH
1596 FRAME_CURSOR_X (f) = (XFASTINT (w->left)
1597 + minmax (0, pos.hpos, width));
44fa5b1e 1598 FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
a2889657
JB
1599 }
1600 /* This doesn't do the trick, because if a window to the right of
1601 this one must be redisplayed, this does nothing because there
44fa5b1e 1602 is nothing in DesiredFrame yet, and then the other window is
a2889657 1603 redisplayed, making likes that are empty in this window's columns.
44fa5b1e 1604 if (XFASTINT (w->width) != FRAME_WIDTH (f))
a2889657
JB
1605 preserve_my_columns (w);
1606 */
1607 goto done;
1608 }
1609 /* Don't bother trying redisplay with same start;
1610 we already know it will lose */
1611 }
1612 /* If current starting point was originally the beginning of a line
1613 but no longer is, find a new starting point. */
265a9e55 1614 else if (!NILP (w->start_at_line_beg)
b16234d8 1615 && !(startp <= BEGV
a2889657
JB
1616 || FETCH_CHAR (startp - 1) == '\n'))
1617 {
1618 goto recenter;
1619 }
1620 else if (just_this_one && !MINI_WINDOW_P (w)
ae3b1442 1621 && PT >= startp
a2889657 1622 && XFASTINT (w->last_modified)
14709f21
JB
1623 /* or else vmotion on first line won't work. */
1624 && ! NILP (w->start_at_line_beg)
a2889657 1625 && ! EQ (w->window_end_valid, Qnil)
86bee31c 1626 && do_id && !current_buffer->clip_changed
a2889657 1627 && !blank_end_of_window
44fa5b1e 1628 && XFASTINT (w->width) == FRAME_WIDTH (f)
bd66d1ba
RS
1629 /* Can't use this case if highlighting a region. */
1630 && !(!NILP (Vtransient_mark_mode)
1631 && !NILP (current_buffer->mark_active))
23c852cb
KH
1632 /* Don't use try_window_id if newline
1633 doesn't display as the end of a line. */
1634 && !(dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, '\n')))
bd66d1ba 1635 && NILP (w->region_showing)
a2889657
JB
1636 && EQ (last_arrow_position, Voverlay_arrow_position)
1637 && EQ (last_arrow_string, Voverlay_arrow_string)
44fa5b1e 1638 && (tem = try_window_id (FRAME_SELECTED_WINDOW (f)))
a2889657
JB
1639 && tem != -2)
1640 {
1641 /* tem > 0 means success. tem == -1 means choose new start.
1642 tem == -2 means try again with same start,
1643 and nothing but whitespace follows the changed stuff.
1644 tem == 0 means try again with same start. */
1645 if (tem > 0)
1646 goto done;
1647 }
1648 else if (startp >= BEGV && startp <= ZV
1649 /* Avoid starting display at end of buffer! */
8de2d90b 1650 && (startp < ZV || startp == BEGV
a2889657
JB
1651 || (XFASTINT (w->last_modified) >= MODIFF)))
1652 {
1653 /* Try to redisplay starting at same place as before */
44fa5b1e 1654 /* If point has not moved off frame, accept the results */
a2889657
JB
1655 try_window (window, startp);
1656 if (cursor_vpos >= 0)
aa6d10fa 1657 {
28995e67
RS
1658 if (!just_this_one || current_buffer->clip_changed
1659 || beg_unchanged < startp)
aa6d10fa
RS
1660 /* Forget any recorded base line for line number display. */
1661 w->base_line_number = Qnil;
1662 goto done;
1663 }
a2889657
JB
1664 else
1665 cancel_my_columns (w);
1666 }
1667
c2213350 1668 XSETFASTINT (w->last_modified, 0);
e481f960
RS
1669 /* Redisplay the mode line. Select the buffer properly for that. */
1670 if (!update_mode_line)
1671 {
1672 set_buffer_temp (old);
f72df6ac 1673 set_buffer_internal_1 (XBUFFER (w->buffer));
e481f960
RS
1674 update_mode_line = 1;
1675 w->update_mode_line = Qt;
1676 }
a2889657
JB
1677
1678 /* Try to scroll by specified few lines */
1679
28995e67 1680 if (scroll_step && !current_buffer->clip_changed)
a2889657 1681 {
ae3b1442 1682 if (PT > startp)
a2889657 1683 {
210e752f 1684 pos = *vmotion (Z - XFASTINT (w->window_end_pos), scroll_step, w);
a2889657
JB
1685 if (pos.vpos >= height)
1686 goto scroll_fail;
1687 }
1688
210e752f 1689 pos = *vmotion (startp, (PT < startp ? - scroll_step : scroll_step), w);
a2889657 1690
ae3b1442 1691 if (PT >= pos.bufpos)
a2889657 1692 {
75c43375
RS
1693 if (! NILP (Vwindow_scroll_functions))
1694 run_hook_with_args_2 (Qwindow_scroll_functions, window,
1695 make_number (pos.bufpos));
a2889657
JB
1696 try_window (window, pos.bufpos);
1697 if (cursor_vpos >= 0)
aa6d10fa 1698 {
28995e67
RS
1699 if (!just_this_one || current_buffer->clip_changed
1700 || beg_unchanged < startp)
aa6d10fa
RS
1701 /* Forget any recorded base line for line number display. */
1702 w->base_line_number = Qnil;
1703 goto done;
1704 }
a2889657
JB
1705 else
1706 cancel_my_columns (w);
1707 }
1708 scroll_fail: ;
1709 }
1710
1711 /* Finally, just choose place to start which centers point */
1712
1713recenter:
aa6d10fa
RS
1714 /* Forget any previously recorded base line for line number display. */
1715 w->base_line_number = Qnil;
1716
210e752f 1717 pos = *vmotion (PT, - (height / 2), w);
75c43375
RS
1718 if (! NILP (Vwindow_scroll_functions))
1719 run_hook_with_args_2 (Qwindow_scroll_functions, window,
1720 make_number (pos.bufpos));
a2889657
JB
1721 try_window (window, pos.bufpos);
1722
1723 startp = marker_position (w->start);
ca26e1c8 1724 w->start_at_line_beg
b16234d8 1725 = (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
a2889657
JB
1726
1727done:
e481f960 1728 if ((update_mode_line
aa6d10fa
RS
1729 /* If window not full width, must redo its mode line
1730 if the window to its side is being redone */
1731 || (!just_this_one && width < FRAME_WIDTH (f) - 1)
155ef550
KH
1732 || INTEGERP (w->base_line_pos)
1733 || (!NILP (w->column_number_displayed)
1734 && XFASTINT (w->column_number_displayed) != current_column ()))
a2889657
JB
1735 && height != XFASTINT (w->height))
1736 display_mode_line (w);
aa6d10fa
RS
1737 if (! line_number_displayed
1738 && ! BUFFERP (w->base_line_pos))
1739 {
1740 w->base_line_pos = Qnil;
1741 w->base_line_number = Qnil;
1742 }
a2889657 1743
7ce2c095 1744 /* When we reach a frame's selected window, redo the frame's menu bar. */
e481f960 1745 if (update_mode_line
d3413a53
RS
1746 && (FRAME_X_P (f)
1747 ?
dc937613 1748#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
d3413a53 1749 FRAME_EXTERNAL_MENU_BAR (f)
76412d64 1750#else
d3413a53 1751 FRAME_MENU_BAR_LINES (f) > 0
76412d64 1752#endif
d3413a53 1753 : FRAME_MENU_BAR_LINES (f) > 0)
7ce2c095
RS
1754 && EQ (FRAME_SELECTED_WINDOW (f), window))
1755 display_menu_bar (w);
1756
88f22aff
JB
1757 finish_scroll_bars:
1758 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
30c566e4 1759 {
b1d1124b 1760 int start, end, whole;
30c566e4 1761
b1d1124b 1762 /* Calculate the start and end positions for the current window.
3505ea70
JB
1763 At some point, it would be nice to choose between scrollbars
1764 which reflect the whole buffer size, with special markers
1765 indicating narrowing, and scrollbars which reflect only the
1766 visible region.
1767
b1d1124b
JB
1768 Note that minibuffers sometimes aren't displaying any text. */
1769 if (! MINI_WINDOW_P (w)
1770 || (w == XWINDOW (minibuf_window) && ! echo_area_glyphs))
1771 {
8a9311d7 1772 whole = ZV - BEGV;
4d641a15 1773 start = marker_position (w->start) - BEGV;
b1d1124b
JB
1774 /* I don't think this is guaranteed to be right. For the
1775 moment, we'll pretend it is. */
85f26be9 1776 end = (Z - XINT (w->window_end_pos)) - BEGV;
3505ea70
JB
1777
1778 if (end < start) end = start;
8a9311d7 1779 if (whole < (end - start)) whole = end - start;
b1d1124b
JB
1780 }
1781 else
1782 start = end = whole = 0;
30c566e4 1783
88f22aff 1784 /* Indicate what this scroll bar ought to be displaying now. */
7eb9ba41 1785 (*set_vertical_scroll_bar_hook) (w, end - start, whole, start);
30c566e4 1786
88f22aff 1787 /* Note that we actually used the scroll bar attached to this window,
30c566e4 1788 so it shouldn't be deleted at the end of redisplay. */
88f22aff 1789 (*redeem_scroll_bar_hook) (w);
30c566e4 1790 }
b1d1124b 1791
f67a0f51 1792 BUF_PT (current_buffer) = opoint;
e481f960 1793 if (update_mode_line)
f72df6ac 1794 set_buffer_internal_1 (old);
e481f960
RS
1795 else
1796 set_buffer_temp (old);
f67a0f51 1797 BUF_PT (current_buffer) = lpoint;
a2889657
JB
1798}
1799\f
1800/* Do full redisplay on one window, starting at position `pos'. */
1801
1802static void
1803try_window (window, pos)
1804 Lisp_Object window;
1805 register int pos;
1806{
1807 register struct window *w = XWINDOW (window);
1808 register int height = window_internal_height (w);
1809 register int vpos = XFASTINT (w->top);
1810 register int last_text_vpos = vpos;
1811 int tab_offset = pos_tab_offset (w, pos);
44fa5b1e 1812 FRAME_PTR f = XFRAME (w->frame);
b1d1124b 1813 int width = window_internal_width (w) - 1;
a2889657
JB
1814 struct position val;
1815
1816 Fset_marker (w->start, make_number (pos), Qnil);
1817 cursor_vpos = -1;
1818 overlay_arrow_seen = 0;
ca26e1c8 1819 zv_strings_seen = 0;
a2889657
JB
1820 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
1821
1822 while (--height >= 0)
1823 {
1824 val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
1825 tab_offset += width;
2b050fec
RS
1826 /* For the first line displayed, display_text_line
1827 subtracts the prompt width from the tab offset.
1828 But it does not affect the value of our variable tab_offset.
1829 So we do the subtraction again,
1830 for the sake of continuation lines of that first line. */
1831 if (MINI_WINDOW_P (w) && vpos == XFASTINT (w->top))
1832 tab_offset -= minibuf_prompt_width;
1833
a2889657
JB
1834 if (val.vpos) tab_offset = 0;
1835 vpos++;
1836 if (pos != val.bufpos)
642eefc6
RS
1837 {
1838 int invis = 0;
e885523c 1839#ifdef USE_TEXT_PROPERTIES
642eefc6
RS
1840 Lisp_Object invis_prop;
1841 invis_prop = Fget_char_property (val.bufpos-1, Qinvisible, window);
1842 invis = TEXT_PROP_MEANS_INVISIBLE (invis_prop);
e885523c 1843#endif
642eefc6
RS
1844
1845 last_text_vpos
1846 /* Next line, unless prev line ended in end of buffer with no cr */
1847 = vpos - (val.vpos
1848 && (FETCH_CHAR (val.bufpos - 1) != '\n' || invis));
1849 }
a2889657
JB
1850 pos = val.bufpos;
1851 }
1852
1853 /* If last line is continued in middle of character,
44fa5b1e 1854 include the split character in the text considered on the frame */
a2889657
JB
1855 if (val.hpos < (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
1856 pos++;
1857
44fa5b1e 1858 /* If bottom just moved off end of frame, change mode line percentage. */
a2889657
JB
1859 if (XFASTINT (w->window_end_pos) == 0
1860 && Z != pos)
1861 w->update_mode_line = Qt;
1862
44fa5b1e 1863 /* Say where last char on frame will be, once redisplay is finished. */
c2213350
KH
1864 XSETFASTINT (w->window_end_pos, Z - pos);
1865 XSETFASTINT (w->window_end_vpos, last_text_vpos - XFASTINT (w->top));
a2889657
JB
1866 /* But that is not valid info until redisplay finishes. */
1867 w->window_end_valid = Qnil;
1868}
1869\f
1870/* Try to redisplay when buffer is modified locally,
1871 computing insert/delete line to preserve text outside
1872 the bounds of the changes.
1873 Return 1 if successful, 0 if if cannot tell what to do,
1874 or -1 to tell caller to find a new window start,
1875 or -2 to tell caller to do normal redisplay with same window start. */
1876
1877static int
1878try_window_id (window)
1879 Lisp_Object window;
1880{
1881 int pos;
1882 register struct window *w = XWINDOW (window);
1883 register int height = window_internal_height (w);
44fa5b1e 1884 FRAME_PTR f = XFRAME (w->frame);
a2889657
JB
1885 int top = XFASTINT (w->top);
1886 int start = marker_position (w->start);
b1d1124b 1887 int width = window_internal_width (w) - 1;
a2889657
JB
1888 int hscroll = XINT (w->hscroll);
1889 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
ca26e1c8 1890 int did_motion;
a2889657
JB
1891 register int vpos;
1892 register int i, tem;
1893 int last_text_vpos = 0;
1894 int stop_vpos;
e24c997d
KH
1895 int selective = (INTEGERP (current_buffer->selective_display)
1896 ? XINT (current_buffer->selective_display)
1897 : !NILP (current_buffer->selective_display) ? -1 : 0);
a2889657
JB
1898
1899 struct position val, bp, ep, xp, pp;
1900 int scroll_amount = 0;
1901 int delta;
d3413a53 1902 int tab_offset, epto, old_tick;
a2889657
JB
1903
1904 if (GPT - BEG < beg_unchanged)
1905 beg_unchanged = GPT - BEG;
1906 if (Z - GPT < end_unchanged)
1907 end_unchanged = Z - GPT;
1908
6a1dc7ac 1909 if (beg_unchanged + BEG < start)
a2889657
JB
1910 return 0; /* Give up if changes go above top of window */
1911
1912 /* Find position before which nothing is changed. */
ca26e1c8 1913 bp = *compute_motion (start, 0, lmargin, 0,
632ab665 1914 min (ZV, beg_unchanged + BEG), height, 0,
e37f06d7 1915 width, hscroll, pos_tab_offset (w, start), w);
a2889657 1916 if (bp.vpos >= height)
6e8290aa 1917 {
632ab665 1918 if (PT < bp.bufpos)
6e8290aa 1919 {
67481ae5
RS
1920 /* All changes are beyond the window end, and point is on the screen.
1921 We don't need to change the text at all.
6e8290aa
JB
1922 But we need to update window_end_pos to account for
1923 any change in buffer size. */
ca26e1c8 1924 bp = *compute_motion (start, 0, lmargin, 0,
67481ae5 1925 ZV, height, 0,
e37f06d7 1926 width, hscroll, pos_tab_offset (w, start), w);
c2213350
KH
1927 XSETFASTINT (w->window_end_vpos, height);
1928 XSETFASTINT (w->window_end_pos, Z - bp.bufpos);
4d641a15 1929 goto findpoint;
6e8290aa
JB
1930 }
1931 return 0;
1932 }
a2889657
JB
1933
1934 vpos = bp.vpos;
1935
44fa5b1e 1936 /* Find beginning of that frame line. Must display from there. */
210e752f 1937 bp = *vmotion (bp.bufpos, 0, w);
a2889657
JB
1938
1939 pos = bp.bufpos;
1940 val.hpos = lmargin;
1941 if (pos < start)
1942 return -1;
1943
ca26e1c8 1944 did_motion = 0;
a2889657 1945 /* If about to start displaying at the beginning of a continuation line,
44fa5b1e 1946 really start with previous frame line, in case it was not
a2889657 1947 continued when last redisplayed */
05ba02eb
JB
1948 if ((bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0)
1949 ||
1950 /* Likewise if we have to worry about selective display. */
9f412332 1951 (selective > 0 && bp.bufpos - 1 == beg_unchanged && vpos > 0))
a2889657 1952 {
210e752f 1953 bp = *vmotion (bp.bufpos, -1, w);
a2889657
JB
1954 --vpos;
1955 pos = bp.bufpos;
1956 }
1957
1958 if (bp.contin && bp.hpos != lmargin)
1959 {
1960 val.hpos = bp.prevhpos - width + lmargin;
ca26e1c8 1961 did_motion = 1;
a2889657
JB
1962 pos--;
1963 }
1964
1965 bp.vpos = vpos;
1966
1967 /* Find first visible newline after which no more is changed. */
1968 tem = find_next_newline (Z - max (end_unchanged, Z - ZV), 1);
9f412332
KH
1969 if (selective > 0)
1970 while (tem < ZV - 1 && (indented_beyond_p (tem, selective)))
a2889657
JB
1971 tem = find_next_newline (tem, 1);
1972
1973 /* Compute the cursor position after that newline. */
ca26e1c8 1974 ep = *compute_motion (pos, vpos, val.hpos, did_motion, tem,
68be917d 1975 height, - (1 << (BITS_PER_SHORT - 1)),
e37f06d7 1976 width, hscroll, pos_tab_offset (w, bp.bufpos), w);
a2889657 1977
44fa5b1e
JB
1978 /* If changes reach past the text available on the frame,
1979 just display rest of frame. */
a2889657
JB
1980 if (ep.bufpos > Z - XFASTINT (w->window_end_pos))
1981 stop_vpos = height;
1982 else
1983 stop_vpos = ep.vpos;
1984
1985 /* If no newline before ep, the line ep is on includes some changes
1986 that must be displayed. Make sure we don't stop before it. */
1987 /* Also, if changes reach all the way until ep.bufpos,
1988 it is possible that something was deleted after the
1989 newline before it, so the following line must be redrawn. */
1990 if (stop_vpos == ep.vpos
1991 && (ep.bufpos == BEGV
1992 || FETCH_CHAR (ep.bufpos - 1) != '\n'
1993 || ep.bufpos == Z - end_unchanged))
1994 stop_vpos = ep.vpos + 1;
1995
1996 cursor_vpos = -1;
1997 overlay_arrow_seen = 0;
ca26e1c8 1998 zv_strings_seen = 0;
a2889657
JB
1999
2000 /* If changes do not reach to bottom of window,
2001 figure out how much to scroll the rest of the window */
2002 if (stop_vpos < height)
2003 {
2004 /* Now determine how far up or down the rest of the window has moved */
2005 epto = pos_tab_offset (w, ep.bufpos);
ca26e1c8 2006 xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
a2889657 2007 Z - XFASTINT (w->window_end_pos),
e37f06d7 2008 10000, 0, width, hscroll, epto, w);
a2889657
JB
2009 scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
2010
44fa5b1e 2011 /* Is everything on frame below the changes whitespace?
a2889657
JB
2012 If so, no scrolling is really necessary. */
2013 for (i = ep.bufpos; i < xp.bufpos; i++)
2014 {
2015 tem = FETCH_CHAR (i);
2016 if (tem != ' ' && tem != '\n' && tem != '\t')
2017 break;
2018 }
2019 if (i == xp.bufpos)
2020 return -2;
2021
e8e536a9
KH
2022 XSETFASTINT (w->window_end_vpos,
2023 XFASTINT (w->window_end_vpos) + scroll_amount);
a2889657 2024
44fa5b1e 2025 /* Before doing any scrolling, verify that point will be on frame. */
ae3b1442 2026 if (PT > ep.bufpos && !(PT <= xp.bufpos && xp.bufpos < height))
a2889657 2027 {
ae3b1442 2028 if (PT <= xp.bufpos)
a2889657 2029 {
ca26e1c8 2030 pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
68be917d 2031 PT, height, - (1 << (BITS_PER_SHORT - 1)),
e37f06d7 2032 width, hscroll, epto, w);
a2889657
JB
2033 }
2034 else
2035 {
ca26e1c8 2036 pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos, 1,
68be917d 2037 PT, height, - (1 << (BITS_PER_SHORT - 1)),
e37f06d7
KH
2038 width, hscroll,
2039 pos_tab_offset (w, xp.bufpos), w);
a2889657 2040 }
ae3b1442 2041 if (pp.bufpos < PT || pp.vpos == height)
a2889657
JB
2042 return 0;
2043 cursor_vpos = pp.vpos + top;
210e752f 2044 cursor_hpos = XFASTINT (w->left) + minmax (0, pp.hpos, width);
a2889657
JB
2045 }
2046
2047 if (stop_vpos - scroll_amount >= height
2048 || ep.bufpos == xp.bufpos)
2049 {
2050 if (scroll_amount < 0)
2051 stop_vpos -= scroll_amount;
2052 scroll_amount = 0;
2053 /* In this path, we have altered window_end_vpos
2054 and not left it negative.
2055 We must make sure that, in case display is preempted
44fa5b1e 2056 before the frame changes to reflect what we do here,
a2889657 2057 further updates will not come to try_window_id
44fa5b1e 2058 and assume the frame and window_end_vpos match. */
a2889657
JB
2059 blank_end_of_window = 1;
2060 }
2061 else if (!scroll_amount)
0d231165
RS
2062 {
2063 /* Even if we don't need to scroll, we must adjust the
2064 charstarts of subsequent lines (that we won't redisplay)
2065 according to the amount of text inserted or deleted. */
2066 int oldpos = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0];
2067 int adjust = ep.bufpos - oldpos;
2068 adjust_window_charstarts (w, ep.vpos + top - 1, adjust);
2069 }
a2889657
JB
2070 else if (bp.bufpos == Z - end_unchanged)
2071 {
2072 /* If reprinting everything is nearly as fast as scrolling,
2073 don't bother scrolling. Can happen if lines are short. */
44fa5b1e 2074 if (scroll_cost (f, bp.vpos + top - scroll_amount,
a2889657
JB
2075 top + height - max (0, scroll_amount),
2076 scroll_amount)
2077 > xp.bufpos - bp.bufpos - 20)
2078 /* Return "try normal display with same window-start."
2079 Too bad we can't prevent further scroll-thinking. */
2080 return -2;
2081 /* If pure deletion, scroll up as many lines as possible.
2082 In common case of killing a line, this can save the
2083 following line from being overwritten by scrolling
2084 and therefore having to be redrawn. */
44fa5b1e 2085 tem = scroll_frame_lines (f, bp.vpos + top - scroll_amount,
d1cb44a4
RS
2086 top + height - max (0, scroll_amount),
2087 scroll_amount, bp.bufpos);
d2f84654
RS
2088 if (!tem)
2089 stop_vpos = height;
2090 else
2091 {
2092 /* scroll_frame_lines did not properly adjust subsequent
2093 lines' charstarts in the case where the text of the
2094 screen line at bp.vpos has changed.
2095 (This can happen in a deletion that ends in mid-line.)
2096 To adjust properly, we need to make things constent at
2097 the position ep.
2098 So do a second adjust to make that happen.
2099 Note that stop_vpos >= ep.vpos, so it is sufficient
2100 to update the charstarts for lines at ep.vpos and below. */
2101 int oldstart
2102 = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0];
2103 adjust_window_charstarts (w, ep.vpos + top - 1,
2104 ep.bufpos - oldstart);
2105 }
a2889657
JB
2106 }
2107 else if (scroll_amount)
2108 {
2109 /* If reprinting everything is nearly as fast as scrolling,
2110 don't bother scrolling. Can happen if lines are short. */
2111 /* Note that if scroll_amount > 0, xp.bufpos - bp.bufpos is an
2112 overestimate of cost of reprinting, since xp.bufpos
2113 would end up below the bottom of the window. */
44fa5b1e 2114 if (scroll_cost (f, ep.vpos + top - scroll_amount,
a2889657
JB
2115 top + height - max (0, scroll_amount),
2116 scroll_amount)
2117 > xp.bufpos - ep.bufpos - 20)
2118 /* Return "try normal display with same window-start."
2119 Too bad we can't prevent further scroll-thinking. */
2120 return -2;
44fa5b1e 2121 tem = scroll_frame_lines (f, ep.vpos + top - scroll_amount,
a2889657 2122 top + height - max (0, scroll_amount),
d1cb44a4 2123 scroll_amount, ep.bufpos);
a2889657
JB
2124 if (!tem) stop_vpos = height;
2125 }
2126 }
2127
2128 /* In any case, do not display past bottom of window */
2129 if (stop_vpos >= height)
2130 {
2131 stop_vpos = height;
2132 scroll_amount = 0;
2133 }
2134
2135 /* Handle case where pos is before w->start --
2136 can happen if part of line had been clipped and is not clipped now */
2137 if (vpos == 0 && pos < marker_position (w->start))
2138 Fset_marker (w->start, make_number (pos), Qnil);
2139
2140 /* Redisplay the lines where the text was changed */
2141 last_text_vpos = vpos;
2142 tab_offset = pos_tab_offset (w, pos);
2143 /* If we are starting display in mid-character, correct tab_offset
2144 to account for passing the line that that character really starts in. */
2145 if (val.hpos < lmargin)
2146 tab_offset += width;
d3413a53 2147 old_tick = MODIFF;
a2889657
JB
2148 while (vpos < stop_vpos)
2149 {
2150 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
d3413a53
RS
2151 /* If display_text_line ran a hook and changed some text,
2152 redisplay all the way to bottom of buffer
2153 So that we show the changes. */
2154 if (old_tick != MODIFF)
2155 stop_vpos = height;
a2889657
JB
2156 tab_offset += width;
2157 if (val.vpos) tab_offset = 0;
2158 if (pos != val.bufpos)
2159 last_text_vpos
2160 /* Next line, unless prev line ended in end of buffer with no cr */
2161 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
2162 pos = val.bufpos;
2163 }
2164
2165 /* There are two cases:
2166 1) we have displayed down to the bottom of the window
2167 2) we have scrolled lines below stop_vpos by scroll_amount */
2168
2169 if (vpos == height)
2170 {
2171 /* If last line is continued in middle of character,
44fa5b1e 2172 include the split character in the text considered on the frame */
a2889657
JB
2173 if (val.hpos < lmargin)
2174 val.bufpos++;
c2213350
KH
2175 XSETFASTINT (w->window_end_vpos, last_text_vpos);
2176 XSETFASTINT (w->window_end_pos, Z - val.bufpos);
a2889657
JB
2177 }
2178
2179 /* If scrolling made blank lines at window bottom,
2180 redisplay to fill those lines */
2181 if (scroll_amount < 0)
2182 {
2183 /* Don't consider these lines for general-purpose scrolling.
2184 That will save time in the scrolling computation. */
44fa5b1e 2185 FRAME_SCROLL_BOTTOM_VPOS (f) = xp.vpos;
a2889657
JB
2186 vpos = xp.vpos;
2187 pos = xp.bufpos;
2188 val.hpos = lmargin;
2189 if (pos == ZV)
2190 vpos = height + scroll_amount;
2191 else if (xp.contin && xp.hpos != lmargin)
2192 {
2193 val.hpos = xp.prevhpos - width + lmargin;
2194 pos--;
2195 }
2196
2197 blank_end_of_window = 1;
2198 tab_offset = pos_tab_offset (w, pos);
2199 /* If we are starting display in mid-character, correct tab_offset
2200 to account for passing the line that that character starts in. */
2201 if (val.hpos < lmargin)
2202 tab_offset += width;
2203
2204 while (vpos < height)
2205 {
2206 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
2207 tab_offset += width;
2208 if (val.vpos) tab_offset = 0;
2209 pos = val.bufpos;
2210 }
2211
2212 /* Here is a case where display_text_line sets cursor_vpos wrong.
2213 Make it be fixed up, below. */
2214 if (xp.bufpos == ZV
ae3b1442 2215 && xp.bufpos == PT)
a2889657
JB
2216 cursor_vpos = -1;
2217 }
2218
44fa5b1e 2219 /* If bottom just moved off end of frame, change mode line percentage. */
a2889657
JB
2220 if (XFASTINT (w->window_end_pos) == 0
2221 && Z != val.bufpos)
2222 w->update_mode_line = Qt;
2223
2224 /* Attempt to adjust end-of-text positions to new bottom line */
2225 if (scroll_amount)
2226 {
2227 delta = height - xp.vpos;
2228 if (delta < 0
2229 || (delta > 0 && xp.bufpos <= ZV)
2230 || (delta == 0 && xp.hpos))
2231 {
210e752f 2232 val = *vmotion (Z - XFASTINT (w->window_end_pos), delta, w);
c2213350 2233 XSETFASTINT (w->window_end_pos, Z - val.bufpos);
e8e536a9
KH
2234 XSETFASTINT (w->window_end_vpos,
2235 XFASTINT (w->window_end_vpos) + val.vpos);
a2889657
JB
2236 }
2237 }
2238
2239 w->window_end_valid = Qnil;
2240
2241 /* If point was not in a line that was displayed, find it */
2242 if (cursor_vpos < 0)
2243 {
4d641a15 2244 findpoint:
ca26e1c8 2245 val = *compute_motion (start, 0, lmargin, 0, PT, 10000, 10000,
e37f06d7 2246 width, hscroll, pos_tab_offset (w, start), w);
44fa5b1e 2247 /* Admit failure if point is off frame now */
a2889657
JB
2248 if (val.vpos >= height)
2249 {
2250 for (vpos = 0; vpos < height; vpos++)
44fa5b1e 2251 cancel_line (vpos + top, f);
a2889657
JB
2252 return 0;
2253 }
2254 cursor_vpos = val.vpos + top;
210e752f 2255 cursor_hpos = XFASTINT (w->left) + minmax (0, val.hpos, width);
a2889657
JB
2256 }
2257
210e752f 2258 FRAME_CURSOR_X (f) = cursor_hpos;
44fa5b1e 2259 FRAME_CURSOR_Y (f) = cursor_vpos;
a2889657
JB
2260
2261 if (debug_end_pos)
2262 {
ca26e1c8 2263 val = *compute_motion (start, 0, lmargin, 0, ZV,
68be917d 2264 height, - (1 << (BITS_PER_SHORT - 1)),
e37f06d7 2265 width, hscroll, pos_tab_offset (w, start), w);
a2889657
JB
2266 if (val.vpos != XFASTINT (w->window_end_vpos))
2267 abort ();
2268 if (XFASTINT (w->window_end_pos)
2269 != Z - val.bufpos)
2270 abort ();
2271 }
2272
2273 return 1;
2274}
2275\f
31b24551
JB
2276/* Mark a section of BUF as modified, but only for the sake of redisplay.
2277 This is useful for recording changes to overlays.
2278
2279 We increment the buffer's modification timestamp and set the
2280 redisplay caches (windows_or_buffers_changed, beg_unchanged, etc)
2281 as if the region of text between START and END had been modified;
2282 the redisplay code will check this against the windows' timestamps,
2283 and redraw the appropriate area of the buffer.
2284
2285 However, if the buffer is unmodified, we bump the last-save
2286 timestamp as well, so that incrementing the timestamp doesn't fool
2287 Emacs into thinking that the buffer's text has been modified.
2288
2289 Tweaking the timestamps shouldn't hurt the first-modification
2290 timestamps recorded in the undo records; those values aren't
2291 written until just before a real text modification is made, so they
2292 will never catch the timestamp value just before this function gets
2293 called. */
2294
2295void
2296redisplay_region (buf, start, end)
2297 struct buffer *buf;
2298 int start, end;
2299{
2300 if (start == end)
2301 return;
2302
2303 if (start > end)
2304 {
2305 int temp = start;
2306 start = end; end = temp;
2307 }
2308
70bcb498
RS
2309 /* If this is a buffer not in the selected window,
2310 we must do other windows. */
2311 if (buf != XBUFFER (XWINDOW (selected_window)->buffer))
2312 windows_or_buffers_changed = 1;
99b9e975
RS
2313 /* If it's not current, we can't use beg_unchanged, end_unchanged for it. */
2314 else if (buf != current_buffer)
2315 windows_or_buffers_changed = 1;
70bcb498
RS
2316 /* If multiple windows show this buffer, we must do other windows. */
2317 else if (buffer_shared > 1)
31b24551
JB
2318 windows_or_buffers_changed = 1;
2319 else
2320 {
2321 if (unchanged_modified == MODIFF)
2322 {
2323 beg_unchanged = start - BEG;
2324 end_unchanged = Z - end;
2325 }
2326 else
2327 {
2328 if (Z - end < end_unchanged)
2329 end_unchanged = Z - end;
2330 if (start - BEG < beg_unchanged)
2331 beg_unchanged = start - BEG;
2332 }
2333 }
2334
2335 /* Increment the buffer's time stamp, but also increment the save
42640f83
RS
2336 and autosave timestamps, so as not to screw up that timekeeping. */
2337 if (BUF_MODIFF (buf) == BUF_SAVE_MODIFF (buf))
2338 BUF_SAVE_MODIFF (buf)++;
31b24551
JB
2339 if (BUF_MODIFF (buf) == buf->auto_save_modified)
2340 buf->auto_save_modified++;
2341
2342 BUF_MODIFF (buf) ++;
2343}
2344
2345\f
278feba9 2346/* Copy LEN glyphs starting address FROM to the rope TO.
f7430cb6 2347 But don't actually copy the parts that would come in before S.
278feba9
RS
2348 Value is TO, advanced past the copied data.
2349 F is the frame we are displaying in. */
a2889657 2350
278feba9
RS
2351static GLYPH *
2352copy_part_of_rope (f, to, s, from, len, face)
2353 FRAME_PTR f;
2354 register GLYPH *to; /* Copy to here. */
a2889657 2355 register GLYPH *s; /* Starting point. */
278feba9
RS
2356 Lisp_Object *from; /* Data to copy. */
2357 int len;
1c2250c2 2358 int face; /* Face to apply to glyphs which don't specify one. */
a2889657 2359{
278feba9
RS
2360 int n = len;
2361 register Lisp_Object *fp = from;
2362 /* These cache the results of the last call to compute_glyph_face. */
2363 int last_code = -1;
2364 int last_merged = 0;
c581d710 2365
87485d6f 2366#ifdef HAVE_FACES
4cdc65eb
KH
2367 if (! FRAME_TERMCAP_P (f))
2368 while (n--)
2369 {
dedd1182 2370 int glyph = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
4cdc65eb
KH
2371 int facecode;
2372
2373 if (FAST_GLYPH_FACE (glyph) == 0)
2374 /* If GLYPH has no face code, use FACE. */
2375 facecode = face;
2376 else if (FAST_GLYPH_FACE (glyph) == last_code)
2377 /* If it's same as previous glyph, use same result. */
2378 facecode = last_merged;
2379 else
2380 {
2381 /* Merge this glyph's face and remember the result. */
2382 last_code = FAST_GLYPH_FACE (glyph);
2383 last_merged = facecode = compute_glyph_face (f, last_code, face);
2384 }
b2a76982 2385
4cdc65eb
KH
2386 if (to >= s)
2387 *to = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), facecode);
2388 ++to;
2389 ++fp;
2390 }
2391 else
2392#endif
2393 while (n--)
2394 {
dedd1182 2395 if (to >= s) *to = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
4cdc65eb
KH
2396 ++to;
2397 ++fp;
2398 }
278feba9 2399 return to;
c581d710
RS
2400}
2401
278feba9
RS
2402/* Correct a glyph by replacing its specified user-level face code
2403 with a displayable computed face code. */
c581d710 2404
278feba9 2405static GLYPH
659a218f 2406fix_glyph (f, glyph, cface)
278feba9
RS
2407 FRAME_PTR f;
2408 GLYPH glyph;
659a218f 2409 int cface;
c581d710 2410{
87485d6f 2411#ifdef HAVE_FACES
659a218f
KH
2412 if (! FRAME_TERMCAP_P (f))
2413 {
2414 if (FAST_GLYPH_FACE (glyph) != 0)
2415 cface = compute_glyph_face (f, FAST_GLYPH_FACE (glyph), cface);
2416 glyph = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), cface);
2417 }
4cdc65eb
KH
2418#endif
2419 return glyph;
a2889657
JB
2420}
2421\f
f4faa47c
JB
2422/* Display one line of window W, starting at position START in W's buffer.
2423
2424 Display starting at horizontal position HPOS, expressed relative to
2425 W's left edge. In situations where the text at START shouldn't
2426 start at the left margin (i.e. when the window is hscrolled, or
2427 we're continuing a line which left off in the midst of a
2428 multi-column character), HPOS should be negative; we throw away
2429 characters up 'til hpos = 0. So, HPOS must take hscrolling into
2430 account.
a2889657
JB
2431
2432 TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
2433
f4faa47c
JB
2434 Display on position VPOS on the frame. It is origin 0, relative to
2435 the top of the frame, not W.
a2889657
JB
2436
2437 Returns a STRUCT POSITION giving character to start next line with
2438 and where to display it, including a zero or negative hpos.
2439 The vpos field is not really a vpos; it is 1 unless the line is continued */
2440
2441struct position val_display_text_line;
2442
2443static struct position *
2444display_text_line (w, start, vpos, hpos, taboffset)
2445 struct window *w;
2446 int start;
2447 int vpos;
2448 int hpos;
2449 int taboffset;
2450{
2451 register int pos = start;
2452 register int c;
2453 register GLYPH *p1;
a2889657
JB
2454 register int pause;
2455 register unsigned char *p;
2456 GLYPH *endp;
d2f84654 2457 register GLYPH *leftmargin;
ca26e1c8 2458 register GLYPH *p1prev;
efc63ef0 2459 register GLYPH *p1start;
ca26e1c8 2460 int prevpos;
efc63ef0 2461 int *charstart;
44fa5b1e 2462 FRAME_PTR f = XFRAME (w->frame);
a2889657 2463 int tab_width = XINT (current_buffer->tab_width);
265a9e55 2464 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
b1d1124b 2465 int width = window_internal_width (w) - 1;
a2889657
JB
2466 struct position val;
2467 int lastpos;
2468 int invis;
642eefc6
RS
2469 int last_invis_skip = 0;
2470 Lisp_Object last_invis_prop;
a2889657 2471 int hscroll = XINT (w->hscroll);
d2f84654
RS
2472 int truncate = (hscroll
2473 || (truncate_partial_width_windows
2474 && XFASTINT (w->width) < FRAME_WIDTH (f))
2475 || !NILP (current_buffer->truncate_lines));
bd66d1ba
RS
2476
2477 /* 1 if we should highlight the region. */
2478 int highlight_region
2479 = !NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active);
2480 int region_beg, region_end;
2481
e24c997d
KH
2482 int selective = (INTEGERP (current_buffer->selective_display)
2483 ? XINT (current_buffer->selective_display)
2484 : !NILP (current_buffer->selective_display) ? -1 : 0);
44fa5b1e 2485 register struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
f908610f 2486 register struct Lisp_Char_Table *dp = window_display_table (w);
68a37fa8
RS
2487
2488 Lisp_Object default_invis_vector[3];
642eefc6
RS
2489 /* Number of characters of ellipsis to display after an invisible line
2490 if it calls for an ellipsis.
2491 Note that this value can be nonzero regardless of whether
2492 selective display is enabled--you must check that separately. */
a2889657 2493 int selective_rlen
642eefc6 2494 = (dp && VECTORP (DISP_INVIS_VECTOR (dp))
68a37fa8 2495 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size
642eefc6 2496 : !NILP (current_buffer->selective_display_ellipses) ? 3 : 0);
68a37fa8
RS
2497 /* This is the sequence of Lisp objects to display
2498 when there are invisible lines. */
2499 Lisp_Object *invis_vector_contents
e24c997d 2500 = (dp && VECTORP (DISP_INVIS_VECTOR (dp))
68a37fa8
RS
2501 ? XVECTOR (DISP_INVIS_VECTOR (dp))->contents
2502 : default_invis_vector);
2503
e24c997d 2504 GLYPH truncator = (dp == 0 || !INTEGERP (DISP_TRUNC_GLYPH (dp))
278feba9 2505 ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
e24c997d 2506 GLYPH continuer = (dp == 0 || !INTEGERP (DISP_CONTINUE_GLYPH (dp))
278feba9 2507 ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
a2889657 2508
31b24551
JB
2509 /* The next buffer location at which the face should change, due
2510 to overlays or text property changes. */
2511 int next_face_change;
2512
ca26e1c8
KH
2513 /* The next location where the `invisible' property changes, or an
2514 overlay starts or ends. */
2515 int next_boundary;
2516
31b24551 2517 /* The face we're currently using. */
1c2250c2 2518 int current_face = 0;
efc63ef0 2519 int i;
31b24551 2520
c2213350 2521 XSETFASTINT (default_invis_vector[2], '.');
68a37fa8
RS
2522 default_invis_vector[0] = default_invis_vector[1] = default_invis_vector[2];
2523
a2889657 2524 hpos += XFASTINT (w->left);
44fa5b1e 2525 get_display_line (f, vpos, XFASTINT (w->left));
54ff581a 2526 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
a2889657 2527
bd66d1ba 2528 /* Show where to highlight the region. */
1613b757 2529 if (highlight_region && XMARKER (current_buffer->mark)->buffer != 0
fba9ce76
RS
2530 /* Maybe highlight only in selected window. */
2531 && (highlight_nonselected_windows
6f139a45 2532 || w == XWINDOW (selected_window)))
bd66d1ba
RS
2533 {
2534 region_beg = marker_position (current_buffer->mark);
2535 if (PT < region_beg)
2536 {
2537 region_end = region_beg;
2538 region_beg = PT;
2539 }
2540 else
2541 region_end = PT;
2542 w->region_showing = Qt;
2543 }
2544 else
2545 region_beg = region_end = -1;
2546
f4faa47c 2547 if (MINI_WINDOW_P (w)
ca26e1c8 2548 && start == BEG
a2889657
JB
2549 && vpos == XFASTINT (w->top))
2550 {
8c5b6a0a 2551 if (! NILP (minibuf_prompt))
f7b4b63a
KH
2552 {
2553 minibuf_prompt_width
8c5b6a0a
KH
2554 = (display_string (w, vpos, XSTRING (minibuf_prompt)->data,
2555 XSTRING (minibuf_prompt)->size, hpos,
ce006f69
RS
2556 /* Display a space if we truncate. */
2557 ' ',
2558 1, -1,
2559 /* Truncate the prompt a little before the
2560 margin, so user input can at least start
2561 on the first line. */
2562 w->width > 10 ? w->width - 4 : -1)
f7b4b63a
KH
2563 - hpos);
2564 hpos += minibuf_prompt_width;
2b050fec 2565 taboffset -= minibuf_prompt_width;
f7b4b63a
KH
2566 }
2567 else
2568 minibuf_prompt_width = 0;
a2889657
JB
2569 }
2570
f4faa47c
JB
2571 /* If we're hscrolled at all, use compute_motion to skip over any
2572 text off the left edge of the window. compute_motion may know
2573 tricks to do this faster than we can. */
2574 if (hpos < 0)
2575 {
2576 struct position *left_edge
ca26e1c8
KH
2577 = compute_motion (pos, vpos, hpos, 0,
2578 ZV, vpos, 0,
f4faa47c
JB
2579 width, hscroll, taboffset, w);
2580
2581 /* Retrieve the buffer position and column provided by
2582 compute_motion. We can't assume that the column will be
2583 zero, because you may have multi-column characters crossing
2584 the left margin.
2585
2586 compute_motion may have moved us past the screen position we
2587 requested, if we hit a multi-column character, or the end of
2588 the line. If so, back up. */
2589 if (left_edge->vpos > vpos
2590 || left_edge->hpos > 0)
2591 {
2592 pos = left_edge->bufpos - 1;
2593 hpos = left_edge->prevhpos;
2594 }
2595 else
2596 {
2597 pos = left_edge->bufpos;
2598 hpos = left_edge->hpos;
2599 }
2600 }
2601
2602 desired_glyphs->bufp[vpos] = start;
a2889657 2603 p1 = desired_glyphs->glyphs[vpos] + hpos;
efc63ef0
RS
2604 p1start = p1;
2605 charstart = desired_glyphs->charstarts[vpos] + hpos;
2606 /* In case we don't ever write anything into it... */
a007eef6 2607 desired_glyphs->charstarts[vpos][XFASTINT (w->left)] = -1;
d2f84654
RS
2608 leftmargin = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
2609 endp = leftmargin + width;
a2889657 2610
1c2250c2
JB
2611 /* Arrange the overlays nicely for our purposes. Usually, we call
2612 display_text_line on only one line at a time, in which case this
2613 can't really hurt too much, or we call it on lines which appear
2614 one after another in the buffer, in which case all calls to
2615 recenter_overlay_lists but the first will be pretty cheap. */
2616 recenter_overlay_lists (current_buffer, pos);
2617
a2889657
JB
2618 /* Loop generating characters.
2619 Stop at end of buffer, before newline,
31b24551
JB
2620 if reach or pass continuation column,
2621 or at face change. */
a2889657 2622 pause = pos;
31b24551 2623 next_face_change = pos;
ca26e1c8
KH
2624 next_boundary = pos;
2625 p1prev = p1;
2626 prevpos = pos;
85bcef6c 2627 while (1)
a2889657 2628 {
31b24551 2629 if (pos >= pause)
a2889657 2630 {
67481ae5
RS
2631 int e_t_h;
2632
ca26e1c8 2633 while (pos == next_boundary)
a2889657 2634 {
ca26e1c8
KH
2635 Lisp_Object position, limit, prop, ww;
2636
2637 /* Display the overlay strings here, unless we're at ZV
2638 and have already displayed the appropriate strings
2639 on an earlier line. */
2640 if (pos < ZV || !zv_strings_seen++)
2641 {
2642 int ovlen;
2643 char *ovstr;
2644 ovlen = overlay_strings (pos, w, &ovstr);
2645 for (; ovlen; ovlen--, ovstr++)
2646 {
2647 if (p1 >= leftmargin && p1 < endp)
2648 *p1 = MAKE_GLYPH (f, *ovstr, current_face);
2649 p1++;
2650 }
2651 }
2652
2653 /* Did we reach point? Record the cursor location. */
2654 if (pos == PT && cursor_vpos < 0)
2655 {
2656 cursor_vpos = vpos;
2657 cursor_hpos = p1 - leftmargin;
2658 }
2659
2660 if (pos >= ZV)
2661 break;
a2889657 2662
c2213350 2663 XSETFASTINT (position, pos);
ca26e1c8
KH
2664 limit = Fnext_overlay_change (position);
2665#ifdef USE_TEXT_PROPERTIES
dfabd9a0
RS
2666 /* This is just an estimate to give reasonable
2667 performance; nothing should go wrong if it is too small. */
fe3d6921 2668 if (XFASTINT (limit) > pos + 50)
c2213350 2669 XSETFASTINT (limit, pos + 50);
ca26e1c8
KH
2670 limit = Fnext_single_property_change (position, Qinvisible,
2671 Fcurrent_buffer (), limit);
2672#endif
2673 next_boundary = XFASTINT (limit);
2674 /* if the `invisible' property is set, we can skip to
2675 the next property change. */
2676 XSETWINDOW (ww, w);
2677 prop = Fget_char_property (position, Qinvisible, ww);
642eefc6 2678 if (TEXT_PROP_MEANS_INVISIBLE (prop))
dfabd9a0 2679 {
ca26e1c8 2680 if (pos < PT && next_boundary >= PT)
dfabd9a0
RS
2681 {
2682 cursor_vpos = vpos;
d2f84654 2683 cursor_hpos = p1 - leftmargin;
dfabd9a0 2684 }
ca26e1c8 2685 pos = next_boundary;
642eefc6
RS
2686 last_invis_skip = pos;
2687 last_invis_prop = prop;
dfabd9a0 2688 }
b0a0fbda 2689 }
ca26e1c8
KH
2690
2691 /* Did we reach point? Record the cursor location. */
2692 if (pos == PT && cursor_vpos < 0)
2693 {
2694 cursor_vpos = vpos;
2695 cursor_hpos = p1 - leftmargin;
2696 }
2697
2698 /* Did we hit the end of the visible region of the buffer?
2699 Stop here. */
2700 if (pos >= ZV)
eff87c2c
RS
2701 {
2702 /* Update charstarts for the end of this line. */
2703 /* Do nothing if off the left edge or at the right edge. */
2704 if (p1 >= leftmargin && p1 + 1 != endp)
2705 {
2706 int *p2x = &charstart[(p1 < leftmargin
2707 ? leftmargin : p1)
2708 - p1start];
2709 *p2x++ = pos;
2710 }
2711 break;
2712 }
b0a0fbda 2713
67481ae5
RS
2714 /* Figure out where (if at all) the
2715 redisplay_end_trigger-hook should run. */
f6fd109b
RS
2716 if (MARKERP (w->redisplay_end_trigger)
2717 && XMARKER (w->redisplay_end_trigger)->buffer != 0)
d3413a53
RS
2718 e_t_h = marker_position (w->redisplay_end_trigger);
2719 else if (INTEGERP (w->redisplay_end_trigger))
2720 e_t_h = XINT (w->redisplay_end_trigger);
67481ae5
RS
2721 else
2722 e_t_h = ZV;
2723
2724 /* If we've gone past the place to run a hook,
2725 run the hook. */
2726 if (pos >= e_t_h && e_t_h != ZV)
2727 {
d3413a53
RS
2728 Frun_hooks (1, &Qredisplay_end_trigger_hook);
2729 w->redisplay_end_trigger = Qnil;
67481ae5 2730 e_t_h = ZV;
f6fd109b
RS
2731 /* Notice if it changed the face of this character. */
2732 next_face_change = pos;
67481ae5
RS
2733 }
2734
f6fd109b
RS
2735#ifdef HAVE_FACES
2736 /* Did we hit a face change? Figure out what face we should
2737 use now. We also hit this the first time through the
2738 loop, to see what face we should start with. */
2739 if (pos >= next_face_change && (FRAME_WINDOW_P (f)))
2740 current_face = compute_char_face (f, w, pos,
2741 region_beg, region_end,
2742 &next_face_change, pos + 50, 0);
2743#endif
2744
67481ae5
RS
2745 /* Compute the next place we need to stop
2746 and do something special; set PAUSE. */
2747
ca26e1c8 2748 pause = ZV;
1c2250c2 2749
ca26e1c8
KH
2750 if (pos < next_boundary && next_boundary < pause)
2751 pause = next_boundary;
1c2250c2
JB
2752 if (pos < next_face_change && next_face_change < pause)
2753 pause = next_face_change;
2754
67481ae5
RS
2755 if (e_t_h < pause)
2756 pause = e_t_h;
2757
31b24551
JB
2758 /* Wouldn't you hate to read the next line to someone over
2759 the phone? */
ae3b1442
KH
2760 if (pos < PT && PT < pause)
2761 pause = PT;
a2889657
JB
2762 if (pos < GPT && GPT < pause)
2763 pause = GPT;
2764
2765 p = &FETCH_CHAR (pos);
2766 }
ca26e1c8 2767
ca26e1c8
KH
2768 if (p1 >= endp)
2769 break;
2770
2771 p1prev = p1;
2772
a2889657 2773 c = *p++;
376b0e59
RS
2774 /* Let a display table override all standard display methods. */
2775 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
2776 {
2777 p1 = copy_part_of_rope (f, p1, leftmargin,
2778 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
2779 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
2780 current_face);
2781 }
2782 else if (c >= 040 && c < 0177)
a2889657 2783 {
d2f84654 2784 if (p1 >= leftmargin)
4cdc65eb 2785 *p1 = MAKE_GLYPH (f, c, current_face);
a2889657
JB
2786 p1++;
2787 }
2788 else if (c == '\n')
2789 {
2790 invis = 0;
642eefc6
RS
2791 if (last_invis_skip == pos
2792 && TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (last_invis_prop))
2793 invis = 1;
ca26e1c8 2794 while (pos + 1 < ZV
a2889657 2795 && selective > 0
9f412332 2796 && indented_beyond_p (pos + 1, selective))
a2889657
JB
2797 {
2798 invis = 1;
2799 pos = find_next_newline (pos + 1, 1);
2800 if (FETCH_CHAR (pos - 1) == '\n')
2801 pos--;
2802 }
d2f84654 2803 if (invis && selective_rlen > 0 && p1 >= leftmargin)
a2889657
JB
2804 {
2805 p1 += selective_rlen;
d2f84654 2806 if (p1 - leftmargin > width)
a2889657 2807 p1 = endp;
278feba9 2808 copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
1c2250c2 2809 (p1 - p1prev), current_face);
a2889657 2810 }
87485d6f 2811#ifdef HAVE_FACES
3c5c35c5
JB
2812 /* Draw the face of the newline character as extending all the
2813 way to the end of the frame line. */
2814 if (current_face)
1105ff20
KH
2815 {
2816 if (p1 < leftmargin)
2817 p1 = leftmargin;
2818 while (p1 < endp)
2819 *p1++ = FAST_MAKE_GLYPH (' ', current_face);
2820 }
3c5c35c5 2821#endif
545e04f6
KH
2822
2823 /* Update charstarts for the newline that ended this line. */
2824 /* Do nothing here for a char that's entirely off the left edge
2825 or if it starts at the right edge. */
2826 if (p1 >= leftmargin && p1prev != endp)
2827 {
2828 /* Store the newline's position into charstarts
2829 for the column where the newline starts.
2830 Store -1 for the rest of the glyphs it occupies. */
2831 int *p2x = &charstart[(p1prev < leftmargin
2832 ? leftmargin : p1prev)
2833 - p1start];
2834 int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
2835
2836 *p2x++ = pos;
2837 while (p2x < p2)
2838 *p2x++ = -1;
2839 }
2840
68a37fa8 2841 break;
a2889657
JB
2842 }
2843 else if (c == '\t')
2844 {
2845 do
2846 {
d2f84654 2847 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2848 *p1 = MAKE_GLYPH (f, ' ', current_face);
a2889657
JB
2849 p1++;
2850 }
d2f84654 2851 while ((p1 - leftmargin + taboffset + hscroll - (hscroll > 0))
a2889657
JB
2852 % tab_width);
2853 }
6e8290aa 2854 else if (c == Ctl ('M') && selective == -1)
a2889657
JB
2855 {
2856 pos = find_next_newline (pos, 1);
2857 if (FETCH_CHAR (pos - 1) == '\n')
2858 pos--;
2859 if (selective_rlen > 0)
2860 {
2861 p1 += selective_rlen;
d2f84654 2862 if (p1 - leftmargin > width)
a2889657 2863 p1 = endp;
278feba9 2864 copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
1c2250c2 2865 (p1 - p1prev), current_face);
a2889657 2866 }
87485d6f 2867#ifdef HAVE_FACES
3c5c35c5
JB
2868 /* Draw the face of the newline character as extending all the
2869 way to the end of the frame line. */
2870 if (current_face)
1105ff20
KH
2871 {
2872 if (p1 < leftmargin)
2873 p1 = leftmargin;
2874 while (p1 < endp)
2875 *p1++ = FAST_MAKE_GLYPH (' ', current_face);
2876 }
3c5c35c5 2877#endif
545e04f6
KH
2878
2879 /* Update charstarts for the ^M that ended this line. */
2880 /* Do nothing here for a char that's entirely off the left edge
2881 or if it starts at the right edge. */
2882 if (p1 >= leftmargin && p1prev != endp)
2883 {
2884 /* Store the newline's position into charstarts
2885 for the column where the newline starts.
2886 Store -1 for the rest of the glyphs it occupies. */
2887 int *p2x = &charstart[(p1prev < leftmargin
2888 ? leftmargin : p1prev)
2889 - p1start];
2890 int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
2891
2892 *p2x++ = pos;
2893 while (p2x < p2)
2894 *p2x++ = -1;
2895 }
68a37fa8 2896 break;
a2889657 2897 }
a2889657
JB
2898 else if (c < 0200 && ctl_arrow)
2899 {
d2f84654 2900 if (p1 >= leftmargin)
e24c997d 2901 *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
278feba9
RS
2902 ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
2903 current_face);
a2889657 2904 p1++;
d2f84654 2905 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2906 *p1 = MAKE_GLYPH (f, c ^ 0100, current_face);
a2889657
JB
2907 p1++;
2908 }
2909 else
2910 {
d2f84654 2911 if (p1 >= leftmargin)
e24c997d 2912 *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
278feba9
RS
2913 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
2914 current_face);
a2889657 2915 p1++;
d2f84654 2916 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2917 *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face);
a2889657 2918 p1++;
d2f84654 2919 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2920 *p1 = MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face);
a2889657 2921 p1++;
d2f84654 2922 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2923 *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face);
a2889657
JB
2924 p1++;
2925 }
31b24551 2926
ca26e1c8 2927 prevpos = pos;
a2889657 2928 pos++;
545e04f6
KH
2929
2930 /* Update charstarts for the character just output. */
2931
2932 /* Do nothing here for a char that's entirely off the left edge. */
2933 if (p1 >= leftmargin)
2934 {
2935 /* Store the char's position into charstarts
2936 for the first glyph occupied by this char.
2937 Store -1 for the rest of the glyphs it occupies. */
2938 if (p1 != p1prev)
2939 {
2940 int *p2x = &charstart[(p1prev < leftmargin
2941 ? leftmargin : p1prev)
2942 - p1start];
2943 int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
2944
2945 if (p2x < p2)
2946 *p2x++ = prevpos;
2947 while (p2x < p2)
2948 *p2x++ = -1;
2949 }
2950 }
a2889657
JB
2951 }
2952
2953 val.hpos = - XINT (w->hscroll);
2954 if (val.hpos)
2955 val.hpos++;
2956
2957 val.vpos = 1;
2958
2959 lastpos = pos;
2960
efc63ef0
RS
2961 /* Store 0 in this charstart line for the positions where
2962 there is no character. But do leave what was recorded
2963 for the character that ended the line. */
85bcef6c
RS
2964 /* Add 1 in the endtest to compensate for the fact that ENDP was
2965 made from WIDTH, which is 1 less than the window's actual
2966 internal width. */
a007eef6
RS
2967 i = p1 - p1start + 1;
2968 if (p1 < leftmargin)
2969 i += leftmargin - p1;
2970 for (; i < endp - p1start + 1; i++)
efc63ef0
RS
2971 charstart[i] = 0;
2972
a2889657
JB
2973 /* Handle continuation in middle of a character */
2974 /* by backing up over it */
2975 if (p1 > endp)
2976 {
5fcbb24d
JB
2977 /* Don't back up if we never actually displayed any text.
2978 This occurs when the minibuffer prompt takes up the whole line. */
2979 if (p1prev)
2980 {
2981 /* Start the next line with that same character */
2982 pos--;
2983 /* but at negative hpos, to skip the columns output on this line. */
2984 val.hpos += p1prev - endp;
2985 }
2986
a2889657
JB
2987 /* Keep in this line everything up to the continuation column. */
2988 p1 = endp;
2989 }
2990
2991 /* Finish deciding which character to start the next line on,
2992 and what hpos to start it at.
2993 Also set `lastpos' to the last position which counts as "on this line"
2994 for cursor-positioning. */
2995
2996 if (pos < ZV)
2997 {
2998 if (FETCH_CHAR (pos) == '\n')
dd5f6267
KH
2999 {
3000 /* If stopped due to a newline, start next line after it */
3001 pos++;
3002 /* Check again for hidden lines, in case the newline occurred exactly
3003 at the right margin. */
3004 while (pos < ZV && selective > 0
3005 && indented_beyond_p (pos, selective))
3006 pos = find_next_newline (pos, 1);
3007 }
a2889657
JB
3008 else
3009 /* Stopped due to right margin of window */
3010 {
3011 if (truncate)
3012 {
278feba9 3013 *p1++ = fix_glyph (f, truncator, 0);
a2889657
JB
3014 /* Truncating => start next line after next newline,
3015 and point is on this line if it is before the newline,
3016 and skip none of first char of next line */
dd5f6267
KH
3017 do
3018 pos = find_next_newline (pos, 1);
3019 while (pos < ZV && selective > 0
3020 && indented_beyond_p (pos, selective));
a2889657
JB
3021 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
3022
3023 lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
3024 }
3025 else
3026 {
278feba9 3027 *p1++ = fix_glyph (f, continuer, 0);
a2889657
JB
3028 val.vpos = 0;
3029 lastpos--;
3030 }
3031 }
3032 }
3033
3034 /* If point is at eol or in invisible text at eol,
44fa5b1e 3035 record its frame location now. */
a2889657 3036
ae3b1442 3037 if (start <= PT && PT <= lastpos && cursor_vpos < 0)
a2889657
JB
3038 {
3039 cursor_vpos = vpos;
d2f84654 3040 cursor_hpos = p1 - leftmargin;
a2889657
JB
3041 }
3042
3043 if (cursor_vpos == vpos)
3044 {
3045 if (cursor_hpos < 0) cursor_hpos = 0;
3046 if (cursor_hpos > width) cursor_hpos = width;
3047 cursor_hpos += XFASTINT (w->left);
44fa5b1e 3048 if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
a2889657 3049 {
b5bbc9a5
KH
3050 if (!(cursor_in_echo_area && FRAME_HAS_MINIBUF_P (f)
3051 && EQ (FRAME_MINIBUF_WINDOW (f), minibuf_window)))
3052 {
3053 FRAME_CURSOR_Y (f) = cursor_vpos;
3054 FRAME_CURSOR_X (f) = cursor_hpos;
3055 }
a2889657
JB
3056
3057 if (w == XWINDOW (selected_window))
3058 {
3059 /* Line is not continued and did not start
3060 in middle of character */
3061 if ((hpos - XFASTINT (w->left)
3062 == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
3063 && val.vpos)
3064 {
3065 this_line_bufpos = start;
3066 this_line_buffer = current_buffer;
3067 this_line_vpos = cursor_vpos;
3068 this_line_start_hpos = hpos;
3069 this_line_endpos = Z - lastpos;
3070 }
3071 else
3072 this_line_bufpos = 0;
3073 }
3074 }
3075 }
3076
3077 /* If hscroll and line not empty, insert truncation-at-left marker */
3078 if (hscroll && lastpos != start)
3079 {
d2f84654
RS
3080 *leftmargin = fix_glyph (f, truncator, 0);
3081 if (p1 <= leftmargin)
3082 p1 = leftmargin + 1;
a2889657
JB
3083 }
3084
44fa5b1e 3085 if (XFASTINT (w->width) + XFASTINT (w->left) != FRAME_WIDTH (f))
a2889657
JB
3086 {
3087 endp++;
d2f84654 3088 if (p1 < leftmargin) p1 = leftmargin;
a2889657 3089 while (p1 < endp) *p1++ = SPACEGLYPH;
b1d1124b 3090
88f22aff
JB
3091 /* Don't draw vertical bars if we're using scroll bars. They're
3092 covered up by the scroll bars, and it's distracting to see
3093 them when the scroll bar windows are flickering around to be
b1d1124b 3094 reconfigured. */
75d13c64
KH
3095 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
3096 {
3097 int i;
3098 for (i = 0; i < FRAME_SCROLL_BAR_COLS (f); i++)
3099 *p1++ = SPACEGLYPH;
3100 }
3101 else
3102 *p1++ = (dp && INTEGERP (DISP_BORDER_GLYPH (dp))
3103 ? DISP_BORDER_GLYPH (dp)
3104 : '|');
a2889657
JB
3105 }
3106 desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
3107 p1 - desired_glyphs->glyphs[vpos]);
3108 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
3109
3110 /* If the start of this line is the overlay arrow-position,
3111 then put the arrow string into the display-line. */
3112
e24c997d 3113 if (MARKERP (Voverlay_arrow_position)
a2889657
JB
3114 && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
3115 && start == marker_position (Voverlay_arrow_position)
e24c997d 3116 && STRINGP (Voverlay_arrow_string)
a2889657
JB
3117 && ! overlay_arrow_seen)
3118 {
3119 unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
3120 int i;
3121 int len = XSTRING (Voverlay_arrow_string)->size;
142be3dd 3122 int arrow_end;
a2889657 3123
b1d1124b
JB
3124 if (len > width)
3125 len = width;
87485d6f 3126#ifdef HAVE_FACES
c4628384
RS
3127 if (!NULL_INTERVAL_P (XSTRING (Voverlay_arrow_string)->intervals))
3128 {
3129 /* If the arrow string has text props, obey them when displaying. */
3130 for (i = 0; i < len; i++)
3131 {
3132 int c = p[i];
3133 Lisp_Object face, ilisp;
3134 int newface;
3135
c2213350 3136 XSETFASTINT (ilisp, i);
c4628384
RS
3137 face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string);
3138 newface = compute_glyph_face_1 (f, face, 0);
3139 leftmargin[i] = FAST_MAKE_GLYPH (c, newface);
3140 }
3141 }
3142 else
87485d6f 3143#endif /* HAVE_FACES */
c4628384
RS
3144 {
3145 for (i = 0; i < len; i++)
3146 leftmargin[i] = p[i];
3147 }
142be3dd
JB
3148
3149 /* Bug in SunOS 4.1.1 compiler requires this intermediate variable. */
d2f84654 3150 arrow_end = (leftmargin - desired_glyphs->glyphs[vpos]) + len;
142be3dd
JB
3151 if (desired_glyphs->used[vpos] < arrow_end)
3152 desired_glyphs->used[vpos] = arrow_end;
a2889657
JB
3153
3154 overlay_arrow_seen = 1;
3155 }
3156
3157 val.bufpos = pos;
3158 val_display_text_line = val;
3159 return &val_display_text_line;
3160}
3161\f
7ce2c095
RS
3162/* Redisplay the menu bar in the frame for window W. */
3163
3164static void
3165display_menu_bar (w)
3166 struct window *w;
3167{
3168 Lisp_Object items, tail;
3169 register int vpos = 0;
3170 register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
3171 int maxendcol = FRAME_WIDTH (f);
3172 int hpos = 0;
8351baf2 3173 int i;
7ce2c095 3174
dc937613
RS
3175#ifdef HAVE_NTGUI
3176 return;
3177#endif
3178
3179#ifdef USE_X_TOOLKIT
d3413a53 3180 if (FRAME_X_P (f))
7ce2c095 3181 return;
dc937613 3182#endif /* USE_X_TOOLKIT */
7ce2c095
RS
3183
3184 get_display_line (f, vpos, 0);
3185
8351baf2
RS
3186 items = FRAME_MENU_BAR_ITEMS (f);
3187 for (i = 0; i < XVECTOR (items)->size; i += 3)
7ce2c095 3188 {
8351baf2
RS
3189 Lisp_Object pos, string;
3190 string = XVECTOR (items)->contents[i + 1];
3191 if (NILP (string))
3192 break;
2d66ad19 3193
c2213350 3194 XSETFASTINT (XVECTOR (items)->contents[i + 2], hpos);
7ce2c095
RS
3195
3196 if (hpos < maxendcol)
3197 hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
3198 XSTRING (string)->data,
90adcf20 3199 XSTRING (string)->size,
278feba9 3200 hpos, 0, 0, hpos, maxendcol);
6b1bbc46 3201 /* Put a space between items. */
2d66ad19
RS
3202 if (hpos < maxendcol)
3203 {
6b1bbc46 3204 int hpos1 = hpos + 1;
278feba9 3205 hpos = display_string (w, vpos, "", 0, hpos, 0, 0,
2d66ad19
RS
3206 min (hpos1, maxendcol), maxendcol);
3207 }
7ce2c095
RS
3208 }
3209
3210 FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
3211 FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
2d66ad19
RS
3212
3213 /* Fill out the line with spaces. */
3214 if (maxendcol > hpos)
278feba9 3215 hpos = display_string (w, vpos, "", 0, hpos, 0, 0, maxendcol, maxendcol);
db6f348c
JB
3216
3217 /* Clear the rest of the lines allocated to the menu bar. */
3218 vpos++;
3219 while (vpos < FRAME_MENU_BAR_LINES (f))
3220 get_display_line (f, vpos++, 0);
7ce2c095
RS
3221}
3222\f
a2889657
JB
3223/* Display the mode line for window w */
3224
3225static void
3226display_mode_line (w)
3227 struct window *w;
3228{
3229 register int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
3230 register int left = XFASTINT (w->left);
3231 register int right = XFASTINT (w->width) + left;
44fa5b1e 3232 register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
a2889657 3233
aa6d10fa 3234 line_number_displayed = 0;
155ef550 3235 w->column_number_displayed = Qnil;
aa6d10fa 3236
44fa5b1e 3237 get_display_line (f, vpos, left);
03b294dc
RS
3238
3239 /* Temporarily make frame F's kboard the current kboard
3240 so that kboard-local variables in the mode_line_format
3241 will get the right values. */
3242 push_frame_kboard (f);
3243
3244 display_mode_element (w, vpos, left, 0, right, right,
3245 current_buffer->mode_line_format);
3246
3247 pop_frame_kboard ();
3248
44fa5b1e 3249 FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
a2889657
JB
3250
3251 /* Make the mode line inverse video if the entire line
3252 is made of mode lines.
3253 I.e. if this window is full width,
3254 or if it is the child of a full width window
3255 (which implies that that window is split side-by-side
3256 and the rest of this line is mode lines of the sibling windows). */
44fa5b1e
JB
3257 if (XFASTINT (w->width) == FRAME_WIDTH (f)
3258 || XFASTINT (XWINDOW (w->parent)->width) == FRAME_WIDTH (f))
3259 FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
87485d6f 3260#ifdef HAVE_FACES
03b294dc 3261 else if (! FRAME_TERMCAP_P (f) && mode_line_inverse_video)
d7eb09a0
RS
3262 {
3263 /* For a partial width window, explicitly set face of each glyph. */
3264 int i;
3265 GLYPH *ptr = FRAME_DESIRED_GLYPHS (f)->glyphs[vpos];
3266 for (i = left; i < right; ++i)
4cdc65eb 3267 ptr[i] = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (ptr[i]), 1);
d7eb09a0 3268 }
4cdc65eb 3269#endif
a2889657
JB
3270}
3271
3272/* Contribute ELT to the mode line for window W.
3273 How it translates into text depends on its data type.
3274
3275 VPOS is the position of the mode line being displayed.
3276
44fa5b1e 3277 HPOS is the position (absolute on frame) where this element's text
a2889657
JB
3278 should start. The output is truncated automatically at the right
3279 edge of window W.
3280
3281 DEPTH is the depth in recursion. It is used to prevent
3282 infinite recursion here.
3283
3284 MINENDCOL is the hpos before which the element may not end.
3285 The element is padded at the right with spaces if nec
3286 to reach this column.
3287
3288 MAXENDCOL is the hpos past which this element may not extend.
3289 If MINENDCOL is > MAXENDCOL, MINENDCOL takes priority.
3290 (This is necessary to make nested padding and truncation work.)
3291
3292 Returns the hpos of the end of the text generated by ELT.
3293 The next element will receive that value as its HPOS arg,
3294 so as to concatenate the elements. */
3295
3296static int
3297display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
3298 struct window *w;
3299 register int vpos, hpos;
3300 int depth;
3301 int minendcol;
3302 register int maxendcol;
3303 register Lisp_Object elt;
3304{
3305 tail_recurse:
3306 if (depth > 10)
3307 goto invalid;
3308
3309 depth++;
3310
0220c518 3311 switch (SWITCH_ENUM_CAST (XTYPE (elt)))
a2889657
JB
3312 {
3313 case Lisp_String:
3314 {
3315 /* A string: output it and check for %-constructs within it. */
3316 register unsigned char c;
3317 register unsigned char *this = XSTRING (elt)->data;
3318
3319 while (hpos < maxendcol && *this)
3320 {
3321 unsigned char *last = this;
3322 while ((c = *this++) != '\0' && c != '%')
3323 ;
3324 if (this - 1 != last)
3325 {
3326 register int lim = --this - last + hpos;
d39b6696
KH
3327 if (frame_title_ptr)
3328 hpos = store_frame_title (last, hpos, min (lim, maxendcol));
3329 else
3330 hpos = display_string (w, vpos, last, -1, hpos, 0, 1,
3331 hpos, min (lim, maxendcol));
a2889657
JB
3332 }
3333 else /* c == '%' */
3334 {
766525bc 3335 register int minendcol;
a2889657
JB
3336 register int spec_width = 0;
3337
3338 /* We can't allow -ve args due to the "%-" construct */
3339 /* Argument specifies minwidth but not maxwidth
3340 (maxwidth can be specified by
3341 (<negative-number> . <stuff>) mode-line elements) */
3342
3343 while ((c = *this++) >= '0' && c <= '9')
3344 {
3345 spec_width = spec_width * 10 + (c - '0');
3346 }
3347
766525bc
RS
3348 minendcol = hpos + spec_width;
3349 if (minendcol > maxendcol)
3350 {
3351 spec_width = maxendcol - hpos;
3352 minendcol = maxendcol;
3353 }
a2889657
JB
3354
3355 if (c == 'M')
3356 hpos = display_mode_element (w, vpos, hpos, depth,
3357 spec_width, maxendcol,
3358 Vglobal_mode_string);
3359 else if (c != 0)
d39b6696 3360 {
766525bc
RS
3361 char *spec = decode_mode_spec (w, c, spec_width,
3362 maxendcol - hpos);
d39b6696 3363 if (frame_title_ptr)
766525bc 3364 hpos = store_frame_title (spec, minendcol, maxendcol);
d39b6696
KH
3365 else
3366 hpos = display_string (w, vpos, spec, -1,
3367 hpos, 0, 1,
766525bc 3368 minendcol, maxendcol);
d39b6696 3369 }
a2889657
JB
3370 }
3371 }
3372 }
3373 break;
3374
3375 case Lisp_Symbol:
3376 /* A symbol: process the value of the symbol recursively
3377 as if it appeared here directly. Avoid error if symbol void.
3378 Special case: if value of symbol is a string, output the string
3379 literally. */
3380 {
3381 register Lisp_Object tem;
3382 tem = Fboundp (elt);
265a9e55 3383 if (!NILP (tem))
a2889657
JB
3384 {
3385 tem = Fsymbol_value (elt);
3386 /* If value is a string, output that string literally:
3387 don't check for % within it. */
e24c997d 3388 if (STRINGP (tem))
d39b6696
KH
3389 {
3390 if (frame_title_ptr)
3391 hpos = store_frame_title (XSTRING (tem)->data,
3392 minendcol, maxendcol);
3393 else
3394 hpos = display_string (w, vpos, XSTRING (tem)->data,
3395 XSTRING (tem)->size,
3396 hpos, 0, 1, minendcol, maxendcol);
3397 }
a2889657
JB
3398 /* Give up right away for nil or t. */
3399 else if (!EQ (tem, elt))
3400 { elt = tem; goto tail_recurse; }
3401 }
3402 }
3403 break;
3404
3405 case Lisp_Cons:
3406 {
3407 register Lisp_Object car, tem;
3408
3409 /* A cons cell: three distinct cases.
3410 If first element is a string or a cons, process all the elements
3411 and effectively concatenate them.
3412 If first element is a negative number, truncate displaying cdr to
3413 at most that many characters. If positive, pad (with spaces)
3414 to at least that many characters.
3415 If first element is a symbol, process the cadr or caddr recursively
3416 according to whether the symbol's value is non-nil or nil. */
3417 car = XCONS (elt)->car;
e24c997d 3418 if (SYMBOLP (car))
a2889657
JB
3419 {
3420 tem = Fboundp (car);
3421 elt = XCONS (elt)->cdr;
e24c997d 3422 if (!CONSP (elt))
a2889657
JB
3423 goto invalid;
3424 /* elt is now the cdr, and we know it is a cons cell.
3425 Use its car if CAR has a non-nil value. */
265a9e55 3426 if (!NILP (tem))
a2889657
JB
3427 {
3428 tem = Fsymbol_value (car);
265a9e55 3429 if (!NILP (tem))
a2889657
JB
3430 { elt = XCONS (elt)->car; goto tail_recurse; }
3431 }
3432 /* Symbol's value is nil (or symbol is unbound)
3433 Get the cddr of the original list
3434 and if possible find the caddr and use that. */
3435 elt = XCONS (elt)->cdr;
265a9e55 3436 if (NILP (elt))
a2889657 3437 break;
e24c997d 3438 else if (!CONSP (elt))
a2889657
JB
3439 goto invalid;
3440 elt = XCONS (elt)->car;
3441 goto tail_recurse;
3442 }
e24c997d 3443 else if (INTEGERP (car))
a2889657
JB
3444 {
3445 register int lim = XINT (car);
3446 elt = XCONS (elt)->cdr;
3447 if (lim < 0)
3448 /* Negative int means reduce maximum width.
3449 DO NOT change MINENDCOL here!
3450 (20 -10 . foo) should truncate foo to 10 col
3451 and then pad to 20. */
3452 maxendcol = min (maxendcol, hpos - lim);
3453 else if (lim > 0)
3454 {
3455 /* Padding specified. Don't let it be more than
3456 current maximum. */
3457 lim += hpos;
3458 if (lim > maxendcol)
3459 lim = maxendcol;
3460 /* If that's more padding than already wanted, queue it.
3461 But don't reduce padding already specified even if
3462 that is beyond the current truncation point. */
3463 if (lim > minendcol)
3464 minendcol = lim;
3465 }
3466 goto tail_recurse;
3467 }
e24c997d 3468 else if (STRINGP (car) || CONSP (car))
a2889657
JB
3469 {
3470 register int limit = 50;
3471 /* LIMIT is to protect against circular lists. */
e24c997d 3472 while (CONSP (elt) && --limit > 0
a2889657
JB
3473 && hpos < maxendcol)
3474 {
3475 hpos = display_mode_element (w, vpos, hpos, depth,
3476 hpos, maxendcol,
3477 XCONS (elt)->car);
3478 elt = XCONS (elt)->cdr;
3479 }
3480 }
3481 }
3482 break;
3483
3484 default:
3485 invalid:
d39b6696
KH
3486 if (frame_title_ptr)
3487 hpos = store_frame_title ("*invalid*", minendcol, maxendcol);
3488 else
3489 hpos = display_string (w, vpos, "*invalid*", -1, hpos, 0, 1,
3490 minendcol, maxendcol);
3491 return hpos;
a2889657
JB
3492 }
3493
a2889657 3494 if (minendcol > hpos)
d39b6696
KH
3495 if (frame_title_ptr)
3496 hpos = store_frame_title ("", minendcol, maxendcol);
3497 else
3498 hpos = display_string (w, vpos, "", 0, hpos, 0, 1, minendcol, maxendcol);
a2889657
JB
3499 return hpos;
3500}
3501\f
766525bc
RS
3502/* Write a null-terminated, right justified decimal representation of
3503 the positive integer D to BUF using a minimal field width WIDTH. */
3504
3505static void
3506pint2str (buf, width, d)
3507 register char *buf;
3508 register int width;
3509 register int d;
3510{
3511 register char *p = buf;
3512
3513 if (d <= 0)
3514 *p++ = '0';
3515 else
3516 while (d > 0)
3517 {
3518 *p++ = d % 10 + '0';
3519 d /= 10;
3520 }
3521 for (width -= (int) (p - buf); width > 0; --width) *p++ = ' ';
3522 *p-- = '\0';
3523 while (p > buf)
3524 {
3525 d = *buf;
3526 *buf++ = *p;
3527 *p-- = d;
3528 }
3529}
3530
a2889657 3531/* Return a string for the output of a mode line %-spec for window W,
766525bc
RS
3532 generated by character C. SPEC_WIDTH is the field width when
3533 padding to the left (%c, %l). The value returned from this
3534 function will later be truncated to width MAXWIDTH. */
a2889657 3535
11e82b76
JB
3536static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
3537
a2889657 3538static char *
766525bc 3539decode_mode_spec (w, c, spec_width, maxwidth)
a2889657
JB
3540 struct window *w;
3541 register char c;
766525bc 3542 register int spec_width;
a2889657
JB
3543 register int maxwidth;
3544{
0b67772d 3545 Lisp_Object obj;
44fa5b1e
JB
3546 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
3547 char *decode_mode_spec_buf = (char *) FRAME_TEMP_GLYPHS (f)->total_contents;
d39b6696 3548 struct buffer *b = XBUFFER (w->buffer);
a2889657 3549
0b67772d 3550 obj = Qnil;
44fa5b1e
JB
3551 if (maxwidth > FRAME_WIDTH (f))
3552 maxwidth = FRAME_WIDTH (f);
a2889657
JB
3553
3554 switch (c)
3555 {
1af9f229
RS
3556 case '*':
3557 if (!NILP (b->read_only))
3558 return "%";
3559 if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
3560 return "*";
3561 return "-";
3562
3563 case '+':
3564 /* This differs from %* only for a modified read-only buffer. */
3565 if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
3566 return "*";
3567 if (!NILP (b->read_only))
3568 return "%";
3569 return "-";
3570
3571 case '&':
3572 /* This differs from %* in ignoring read-only-ness. */
3573 if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
3574 return "*";
3575 return "-";
3576
3577 case '%':
3578 return "%";
3579
3580 case '[':
3581 {
3582 int i;
3583 char *p;
3584
3585 if (command_loop_level > 5)
3586 return "[[[... ";
3587 p = decode_mode_spec_buf;
3588 for (i = 0; i < command_loop_level; i++)
3589 *p++ = '[';
3590 *p = 0;
3591 return decode_mode_spec_buf;
3592 }
3593
3594 case ']':
3595 {
3596 int i;
3597 char *p;
3598
3599 if (command_loop_level > 5)
3600 return " ...]]]";
3601 p = decode_mode_spec_buf;
3602 for (i = 0; i < command_loop_level; i++)
3603 *p++ = ']';
3604 *p = 0;
3605 return decode_mode_spec_buf;
3606 }
3607
3608 case '-':
3609 {
3610 register char *p;
3611 register int i;
3612
3613 if (maxwidth < sizeof (lots_of_dashes))
3614 return lots_of_dashes;
3615 else
3616 {
3617 for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
3618 *p++ = '-';
3619 *p = '\0';
3620 }
3621 return decode_mode_spec_buf;
3622 }
3623
a2889657 3624 case 'b':
d39b6696 3625 obj = b->name;
a2889657
JB
3626#if 0
3627 if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
3628 {
3629 bcopy (XSTRING (obj)->data, decode_mode_spec_buf, maxwidth - 1);
3630 decode_mode_spec_buf[maxwidth - 1] = '\\';
3631 decode_mode_spec_buf[maxwidth] = '\0';
3632 return decode_mode_spec_buf;
3633 }
3634#endif
3635 break;
3636
1af9f229
RS
3637 case 'c':
3638 {
3639 int col = current_column ();
3640 XSETFASTINT (w->column_number_displayed, col);
766525bc 3641 pint2str (decode_mode_spec_buf, spec_width, col);
1af9f229
RS
3642 return decode_mode_spec_buf;
3643 }
3644
3645 case 'F':
3646 /* %F displays the frame name. */
9cb61f8d 3647#ifdef MULTI_FRAME
1af9f229 3648 return (char *) XSTRING (selected_frame->name)->data;
9cb61f8d
RS
3649#else
3650 return "Emacs";
3651#endif
1af9f229 3652
a2889657 3653 case 'f':
d39b6696 3654 obj = b->filename;
a2889657 3655#if 0
265a9e55 3656 if (NILP (obj))
a2889657 3657 return "[none]";
e24c997d 3658 else if (STRINGP (obj) && XSTRING (obj)->size > maxwidth)
a2889657
JB
3659 {
3660 bcopy ("...", decode_mode_spec_buf, 3);
3661 bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
3662 decode_mode_spec_buf + 3, maxwidth - 3);
3663 return decode_mode_spec_buf;
3664 }
3665#endif
3666 break;
3667
aa6d10fa
RS
3668 case 'l':
3669 {
3670 int startpos = marker_position (w->start);
3671 int line, linepos, topline;
3672 int nlines, junk;
3673 Lisp_Object tem;
3674 int height = XFASTINT (w->height);
3675
3676 /* If we decided that this buffer isn't suitable for line numbers,
3677 don't forget that too fast. */
3678 if (EQ (w->base_line_pos, w->buffer))
766525bc 3679 goto no_value;
aa6d10fa
RS
3680
3681 /* If the buffer is very big, don't waste time. */
d39b6696 3682 if (BUF_ZV (b) - BUF_BEGV (b) > line_number_display_limit)
aa6d10fa
RS
3683 {
3684 w->base_line_pos = Qnil;
3685 w->base_line_number = Qnil;
766525bc 3686 goto no_value;
aa6d10fa
RS
3687 }
3688
3689 if (!NILP (w->base_line_number)
3690 && !NILP (w->base_line_pos)
3691 && XFASTINT (w->base_line_pos) <= marker_position (w->start))
3692 {
3693 line = XFASTINT (w->base_line_number);
3694 linepos = XFASTINT (w->base_line_pos);
3695 }
3696 else
3697 {
3698 line = 1;
d39b6696 3699 linepos = BUF_BEGV (b);
aa6d10fa
RS
3700 }
3701
3702 /* Count lines from base line to window start position. */
3703 nlines = display_count_lines (linepos, startpos, startpos, &junk);
3704
3705 topline = nlines + line;
3706
3707 /* Determine a new base line, if the old one is too close
3708 or too far away, or if we did not have one.
3709 "Too close" means it's plausible a scroll-down would
3710 go back past it. */
d39b6696 3711 if (startpos == BUF_BEGV (b))
aa6d10fa 3712 {
c2213350
KH
3713 XSETFASTINT (w->base_line_number, topline);
3714 XSETFASTINT (w->base_line_pos, BUF_BEGV (b));
aa6d10fa
RS
3715 }
3716 else if (nlines < height + 25 || nlines > height * 3 + 50
d39b6696 3717 || linepos == BUF_BEGV (b))
aa6d10fa 3718 {
d39b6696 3719 int limit = BUF_BEGV (b);
aa6d10fa
RS
3720 int position;
3721 int distance = (height * 2 + 30) * 200;
3722
3723 if (startpos - distance > limit)
3724 limit = startpos - distance;
3725
3726 nlines = display_count_lines (startpos, limit,
3727 -(height * 2 + 30),
3728 &position);
3729 /* If we couldn't find the lines we wanted within
3730 200 chars per line,
3731 give up on line numbers for this window. */
3732 if (position == startpos - distance)
3733 {
3734 w->base_line_pos = w->buffer;
3735 w->base_line_number = Qnil;
766525bc 3736 goto no_value;
aa6d10fa
RS
3737 }
3738
c2213350
KH
3739 XSETFASTINT (w->base_line_number, topline - nlines);
3740 XSETFASTINT (w->base_line_pos, position);
aa6d10fa
RS
3741 }
3742
3743 /* Now count lines from the start pos to point. */
3744 nlines = display_count_lines (startpos, PT, PT, &junk);
3745
3746 /* Record that we did display the line number. */
3747 line_number_displayed = 1;
3748
3749 /* Make the string to show. */
766525bc 3750 pint2str (decode_mode_spec_buf, spec_width, topline + nlines);
aa6d10fa 3751 return decode_mode_spec_buf;
766525bc
RS
3752 no_value:
3753 {
3754 char* p = decode_mode_spec_buf;
3755 for (spec_width -= 2; spec_width > 0; --spec_width) *p++ = ' ';
3756 strcpy (p, "??");
3757 return decode_mode_spec_buf;
3758 }
aa6d10fa
RS
3759 }
3760 break;
3761
a2889657 3762 case 'm':
d39b6696 3763 obj = b->mode_name;
a2889657
JB
3764 break;
3765
3766 case 'n':
d39b6696 3767 if (BUF_BEGV (b) > BUF_BEG (b) || BUF_ZV (b) < BUF_Z (b))
a2889657
JB
3768 return " Narrow";
3769 break;
3770
a2889657
JB
3771 case 'p':
3772 {
3773 int pos = marker_position (w->start);
d39b6696 3774 int total = BUF_ZV (b) - BUF_BEGV (b);
a2889657 3775
d39b6696 3776 if (XFASTINT (w->window_end_pos) <= BUF_Z (b) - BUF_ZV (b))
a2889657 3777 {
d39b6696 3778 if (pos <= BUF_BEGV (b))
a2889657
JB
3779 return "All";
3780 else
3781 return "Bottom";
3782 }
d39b6696 3783 else if (pos <= BUF_BEGV (b))
a2889657
JB
3784 return "Top";
3785 else
3786 {
d39b6696 3787 total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total;
a2889657
JB
3788 /* We can't normally display a 3-digit number,
3789 so get us a 2-digit number that is close. */
3790 if (total == 100)
3791 total = 99;
3792 sprintf (decode_mode_spec_buf, "%2d%%", total);
3793 return decode_mode_spec_buf;
3794 }
3795 }
3796
8ffcb79f
RS
3797 /* Display percentage of size above the bottom of the screen. */
3798 case 'P':
3799 {
3800 int toppos = marker_position (w->start);
d39b6696
KH
3801 int botpos = BUF_Z (b) - XFASTINT (w->window_end_pos);
3802 int total = BUF_ZV (b) - BUF_BEGV (b);
8ffcb79f 3803
d39b6696 3804 if (botpos >= BUF_ZV (b))
8ffcb79f 3805 {
d39b6696 3806 if (toppos <= BUF_BEGV (b))
8ffcb79f
RS
3807 return "All";
3808 else
3809 return "Bottom";
3810 }
3811 else
3812 {
d39b6696 3813 total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total;
8ffcb79f
RS
3814 /* We can't normally display a 3-digit number,
3815 so get us a 2-digit number that is close. */
3816 if (total == 100)
3817 total = 99;
d39b6696 3818 if (toppos <= BUF_BEGV (b))
8ffcb79f
RS
3819 sprintf (decode_mode_spec_buf, "Top%2d%%", total);
3820 else
3821 sprintf (decode_mode_spec_buf, "%2d%%", total);
3822 return decode_mode_spec_buf;
3823 }
3824 }
3825
1af9f229
RS
3826 case 's':
3827 /* status of process */
3828 obj = Fget_buffer_process (w->buffer);
3829 if (NILP (obj))
3830 return "no process";
3831#ifdef subprocesses
3832 obj = Fsymbol_name (Fprocess_status (obj));
3833#endif
3834 break;
d39b6696 3835
1af9f229
RS
3836 case 't': /* indicate TEXT or BINARY */
3837#ifdef MODE_LINE_BINARY_TEXT
3838 return MODE_LINE_BINARY_TEXT (b);
3839#else
3840 return "T";
3841#endif
a2889657 3842 }
d39b6696 3843
e24c997d 3844 if (STRINGP (obj))
a2889657
JB
3845 return (char *) XSTRING (obj)->data;
3846 else
3847 return "";
3848}
59b49f63
RS
3849\f
3850/* Search for COUNT instances of a line boundary, which means either a
3851 newline or (if selective display enabled) a carriage return.
3852 Start at START. If COUNT is negative, search backwards.
3853
3854 If we find COUNT instances, set *SHORTAGE to zero, and return the
3855 position after the COUNTth match. Note that for reverse motion
3856 this is not the same as the usual convention for Emacs motion commands.
3857
3858 If we don't find COUNT instances before reaching the end of the
3859 buffer (or the beginning, if scanning backwards), set *SHORTAGE to
3860 the number of line boundaries left unfound, and return the end of the
3861 buffer we bumped up against. */
3862
3863static int
3864display_scan_buffer (start, count, shortage)
3865 int *shortage, start;
3866 register int count;
3867{
3868 int limit = ((count > 0) ? ZV - 1 : BEGV);
3869 int direction = ((count > 0) ? 1 : -1);
3870
3871 register unsigned char *cursor;
3872 unsigned char *base;
3873
3874 register int ceiling;
3875 register unsigned char *ceiling_addr;
3876
3877 /* If we are not in selective display mode,
3878 check only for newlines. */
3879 if (! (!NILP (current_buffer->selective_display)
3880 && !INTEGERP (current_buffer->selective_display)))
ae474ea9 3881 return scan_buffer ('\n', start, 0, count, shortage, 0);
59b49f63
RS
3882
3883 /* The code that follows is like scan_buffer
3884 but checks for either newline or carriage return. */
3885
3886 if (shortage != 0)
3887 *shortage = 0;
3888
3889 if (count > 0)
3890 while (start != limit + 1)
3891 {
3892 ceiling = BUFFER_CEILING_OF (start);
3893 ceiling = min (limit, ceiling);
3894 ceiling_addr = &FETCH_CHAR (ceiling) + 1;
3895 base = (cursor = &FETCH_CHAR (start));
3896 while (1)
3897 {
3898 while (*cursor != '\n' && *cursor != 015 && ++cursor != ceiling_addr)
3899 ;
3900 if (cursor != ceiling_addr)
3901 {
3902 if (--count == 0)
3903 {
3904 immediate_quit = 0;
3905 return (start + cursor - base + 1);
3906 }
3907 else
3908 if (++cursor == ceiling_addr)
3909 break;
3910 }
3911 else
3912 break;
3913 }
3914 start += cursor - base;
3915 }
3916 else
3917 {
3918 start--; /* first character we scan */
3919 while (start > limit - 1)
3920 { /* we WILL scan under start */
3921 ceiling = BUFFER_FLOOR_OF (start);
3922 ceiling = max (limit, ceiling);
3923 ceiling_addr = &FETCH_CHAR (ceiling) - 1;
3924 base = (cursor = &FETCH_CHAR (start));
3925 cursor++;
3926 while (1)
3927 {
3928 while (--cursor != ceiling_addr
3929 && *cursor != '\n' && *cursor != 015)
3930 ;
3931 if (cursor != ceiling_addr)
3932 {
3933 if (++count == 0)
3934 {
3935 immediate_quit = 0;
3936 return (start + cursor - base + 1);
3937 }
3938 }
3939 else
3940 break;
3941 }
3942 start += cursor - base;
3943 }
3944 }
3945
3946 if (shortage != 0)
3947 *shortage = count * direction;
3948 return (start + ((direction == 1 ? 0 : 1)));
3949}
aa6d10fa
RS
3950
3951/* Count up to N lines starting from FROM.
3952 But don't go beyond LIMIT.
3953 Return the number of lines thus found (always positive).
3954 Store the position after what was found into *POS_PTR. */
3955
3956static int
3957display_count_lines (from, limit, n, pos_ptr)
3958 int from, limit, n;
3959 int *pos_ptr;
3960{
3961 int oldbegv = BEGV;
3962 int oldzv = ZV;
3963 int shortage = 0;
3964
3965 if (limit < from)
3966 BEGV = limit;
3967 else
3968 ZV = limit;
3969
59b49f63 3970 *pos_ptr = display_scan_buffer (from, n, &shortage);
aa6d10fa
RS
3971
3972 ZV = oldzv;
3973 BEGV = oldbegv;
3974
3975 if (n < 0)
3976 /* When scanning backwards, scan_buffer stops *after* the last newline
3977 it finds, but does count it. Compensate for that. */
3978 return - n - shortage - (*pos_ptr != limit);
3979 return n - shortage;
3980}
a2889657
JB
3981\f
3982/* Display STRING on one line of window W, starting at HPOS.
3983 Display at position VPOS. Caller should have done get_display_line.
11e82b76 3984 If VPOS == -1, display it as the current frame's title.
90adcf20 3985 LENGTH is the length of STRING, or -1 meaning STRING is null-terminated.
a2889657
JB
3986
3987 TRUNCATE is GLYPH to display at end if truncated. Zero for none.
3988
3989 MINCOL is the first column ok to end at. (Pad with spaces to this col.)
3990 MAXCOL is the last column ok to end at. Truncate here.
3991 -1 for MINCOL or MAXCOL means no explicit minimum or maximum.
44fa5b1e 3992 Both count from the left edge of the frame, as does HPOS.
a2889657
JB
3993 The right edge of W is an implicit maximum.
3994 If TRUNCATE is nonzero, the implicit maximum is one column before the edge.
3995
278feba9
RS
3996 OBEY_WINDOW_WIDTH says to put spaces or vertical bars
3997 at the place where the current window ends in this line
3998 and not display anything beyond there. Otherwise, only MAXCOL
3999 controls where to stop output.
4000
4001 Returns ending hpos. */
a2889657
JB
4002
4003static int
278feba9
RS
4004display_string (w, vpos, string, length, hpos, truncate,
4005 obey_window_width, mincol, maxcol)
a2889657
JB
4006 struct window *w;
4007 unsigned char *string;
90adcf20 4008 int length;
a2889657
JB
4009 int vpos, hpos;
4010 GLYPH truncate;
278feba9 4011 int obey_window_width;
a2889657
JB
4012 int mincol, maxcol;
4013{
4014 register int c;
d3413a53 4015 int truncated;
a2889657
JB
4016 register GLYPH *p1;
4017 int hscroll = XINT (w->hscroll);
253c7d2f 4018 int tab_width = XINT (XBUFFER (w->buffer)->tab_width);
a2889657
JB
4019 register GLYPH *start;
4020 register GLYPH *end;
b1d1124b
JB
4021 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
4022 struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
a2889657
JB
4023 GLYPH *p1start = desired_glyphs->glyphs[vpos] + hpos;
4024 int window_width = XFASTINT (w->width);
4025
4026 /* Use the standard display table, not the window's display table.
4027 We don't want the mode line in rot13. */
f908610f 4028 register struct Lisp_Char_Table *dp = 0;
efc63ef0 4029 int i;
a2889657 4030
f908610f
RS
4031 if (DISP_TABLE_P (Vstandard_display_table))
4032 dp = XCHAR_TABLE (Vstandard_display_table);
a2889657 4033
54ff581a 4034 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
a2889657
JB
4035
4036 p1 = p1start;
4037 start = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
a2889657 4038
278feba9 4039 if (obey_window_width)
b1d1124b 4040 {
278feba9
RS
4041 end = start + window_width - (truncate != 0);
4042
4043 if ((window_width + XFASTINT (w->left)) != FRAME_WIDTH (f))
b1d1124b 4044 {
278feba9
RS
4045 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4046 {
4047 int i;
b1d1124b 4048
5802e919 4049 for (i = 0; i < FRAME_SCROLL_BAR_COLS (f); i++)
278feba9
RS
4050 *end-- = ' ';
4051 }
4052 else
4053 *end-- = '|';
b1d1124b 4054 }
b1d1124b 4055 }
a2889657 4056
278feba9
RS
4057 if (! obey_window_width
4058 || (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol))
a2889657 4059 end = desired_glyphs->glyphs[vpos] + maxcol;
278feba9 4060
efc63ef0 4061 /* Store 0 in charstart for these columns. */
bd5dec8e 4062 for (i = (hpos >= 0 ? hpos : 0); i < end - p1start + hpos; i++)
efc63ef0
RS
4063 desired_glyphs->charstarts[vpos][i] = 0;
4064
a2889657
JB
4065 if (maxcol >= 0 && mincol > maxcol)
4066 mincol = maxcol;
4067
d3413a53
RS
4068 /* We set truncated to 1 if we get stopped by trying to pass END
4069 (that is, trying to pass MAXCOL.) */
4070 truncated = 0;
4071 while (1)
a2889657 4072 {
90adcf20
RS
4073 if (length == 0)
4074 break;
a2889657 4075 c = *string++;
90adcf20
RS
4076 /* Specified length. */
4077 if (length >= 0)
4078 length--;
4079 /* Unspecified length (null-terminated string). */
4080 else if (c == 0)
4081 break;
4082
d3413a53
RS
4083 if (p1 >= end)
4084 {
4085 truncated = 1;
4086 break;
4087 }
4088
376b0e59
RS
4089 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
4090 {
4091 p1 = copy_part_of_rope (f, p1, start,
4092 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
4093 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
4094 0);
4095 }
4096 else if (c >= 040 && c < 0177)
a2889657
JB
4097 {
4098 if (p1 >= start)
4099 *p1 = c;
4100 p1++;
4101 }
4102 else if (c == '\t')
4103 {
4104 do
4105 {
4106 if (p1 >= start && p1 < end)
4107 *p1 = SPACEGLYPH;
4108 p1++;
4109 }
4110 while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
4111 }
ded34426 4112 else if (c < 0200 && ! NILP (buffer_defaults.ctl_arrow))
a2889657
JB
4113 {
4114 if (p1 >= start)
e24c997d 4115 *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
278feba9
RS
4116 ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
4117 0);
a2889657 4118 p1++;
6e8290aa 4119 if (p1 >= start && p1 < end)
a2889657
JB
4120 *p1 = c ^ 0100;
4121 p1++;
4122 }
4123 else
4124 {
4125 if (p1 >= start)
e24c997d 4126 *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
278feba9
RS
4127 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
4128 0);
a2889657 4129 p1++;
6e8290aa 4130 if (p1 >= start && p1 < end)
a2889657
JB
4131 *p1 = (c >> 6) + '0';
4132 p1++;
6e8290aa 4133 if (p1 >= start && p1 < end)
a2889657
JB
4134 *p1 = (7 & (c >> 3)) + '0';
4135 p1++;
6e8290aa 4136 if (p1 >= start && p1 < end)
a2889657
JB
4137 *p1 = (7 & c) + '0';
4138 p1++;
4139 }
4140 }
4141
d3413a53 4142 if (truncated)
a2889657
JB
4143 {
4144 p1 = end;
278feba9 4145 if (truncate) *p1++ = fix_glyph (f, truncate, 0);
a2889657
JB
4146 }
4147 else if (mincol >= 0)
4148 {
4149 end = desired_glyphs->glyphs[vpos] + mincol;
4150 while (p1 < end)
4151 *p1++ = SPACEGLYPH;
4152 }
4153
4154 {
4155 register int len = p1 - desired_glyphs->glyphs[vpos];
4156
4157 if (len > desired_glyphs->used[vpos])
4158 desired_glyphs->used[vpos] = len;
4159 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
4160
4161 return len;
4162 }
4163}
4164\f
642eefc6
RS
4165/* This is like a combination of memq and assq.
4166 Return 1 if PROPVAL appears as an element of LIST
4167 or as the car of an element of LIST.
af460d46
RS
4168 If PROPVAL is a list, compare each element against LIST
4169 in that way, and return 1 if any element of PROPVAL is found in LIST.
642eefc6
RS
4170 Otherwise return 0.
4171 This function cannot quit. */
4172
4173int
4174invisible_p (propval, list)
4175 register Lisp_Object propval;
4176 Lisp_Object list;
4177{
af460d46
RS
4178 register Lisp_Object tail, proptail;
4179 for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
642eefc6
RS
4180 {
4181 register Lisp_Object tem;
af460d46 4182 tem = XCONS (tail)->car;
642eefc6
RS
4183 if (EQ (propval, tem))
4184 return 1;
4185 if (CONSP (tem) && EQ (propval, XCONS (tem)->car))
4186 return 1;
4187 }
af460d46
RS
4188 if (CONSP (propval))
4189 for (proptail = propval; CONSP (proptail);
4190 proptail = XCONS (proptail)->cdr)
4191 {
4192 Lisp_Object propelt;
4193 propelt = XCONS (proptail)->car;
4194 for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
4195 {
4196 register Lisp_Object tem;
4197 tem = XCONS (tail)->car;
4198 if (EQ (propelt, tem))
4199 return 1;
4200 if (CONSP (tem) && EQ (propelt, XCONS (tem)->car))
4201 return 1;
4202 }
4203 }
642eefc6
RS
4204 return 0;
4205}
4206
4207/* Return 1 if PROPVAL appears as the car of an element of LIST
4208 and the cdr of that element is non-nil.
af460d46
RS
4209 If PROPVAL is a list, check each element of PROPVAL in that way,
4210 and the first time some element is found,
4211 return 1 if the cdr of that element is non-nil.
642eefc6
RS
4212 Otherwise return 0.
4213 This function cannot quit. */
4214
4215int
4216invisible_ellipsis_p (propval, list)
4217 register Lisp_Object propval;
4218 Lisp_Object list;
4219{
af460d46
RS
4220 register Lisp_Object tail, proptail;
4221 for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
642eefc6
RS
4222 {
4223 register Lisp_Object tem;
af460d46 4224 tem = XCONS (tail)->car;
642eefc6
RS
4225 if (CONSP (tem) && EQ (propval, XCONS (tem)->car))
4226 return ! NILP (XCONS (tem)->cdr);
4227 }
af460d46
RS
4228 if (CONSP (propval))
4229 for (proptail = propval; CONSP (proptail);
4230 proptail = XCONS (proptail)->cdr)
4231 {
4232 Lisp_Object propelt;
4233 propelt = XCONS (proptail)->car;
4234 for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
4235 {
4236 register Lisp_Object tem;
4237 tem = XCONS (tail)->car;
4238 if (CONSP (tem) && EQ (propelt, XCONS (tem)->car))
4239 return ! NILP (XCONS (tem)->cdr);
4240 }
4241 }
642eefc6
RS
4242 return 0;
4243}
4244\f
a2889657
JB
4245void
4246syms_of_xdisp ()
4247{
cf074754
RS
4248 staticpro (&Qmenu_bar_update_hook);
4249 Qmenu_bar_update_hook = intern ("menu-bar-update-hook");
4250
d46fb96a 4251 staticpro (&Qoverriding_terminal_local_map);
7079aefa 4252 Qoverriding_terminal_local_map = intern ("overriding-terminal-local-map");
d46fb96a 4253
399164b4
KH
4254 staticpro (&Qoverriding_local_map);
4255 Qoverriding_local_map = intern ("overriding-local-map");
4256
75c43375
RS
4257 staticpro (&Qwindow_scroll_functions);
4258 Qwindow_scroll_functions = intern ("window-scroll-functions");
4259
67481ae5
RS
4260 staticpro (&Qredisplay_end_trigger_hook);
4261 Qredisplay_end_trigger_hook = intern ("redisplay-end-trigger-hook");
4262
a2889657
JB
4263 staticpro (&last_arrow_position);
4264 staticpro (&last_arrow_string);
4265 last_arrow_position = Qnil;
4266 last_arrow_string = Qnil;
4267
4268 DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
8c45d522 4269 "String (or mode line construct) included (normally) in `mode-line-format'.");
a2889657
JB
4270 Vglobal_mode_string = Qnil;
4271
4272 DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
4273 "Marker for where to display an arrow on top of the buffer text.\n\
4274This must be the beginning of a line in order to work.\n\
4275See also `overlay-arrow-string'.");
4276 Voverlay_arrow_position = Qnil;
4277
4278 DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
4279 "String to display as an arrow. See also `overlay-arrow-position'.");
4280 Voverlay_arrow_string = Qnil;
4281
4282 DEFVAR_INT ("scroll-step", &scroll_step,
4283 "*The number of lines to try scrolling a window by when point moves out.\n\
44fa5b1e
JB
4284If that fails to bring point back on frame, point is centered instead.\n\
4285If this is zero, point is always centered after it moves off frame.");
a2889657
JB
4286
4287 DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
4288
4289 DEFVAR_BOOL ("truncate-partial-width-windows",
4290 &truncate_partial_width_windows,
44fa5b1e 4291 "*Non-nil means truncate lines in all windows less than full frame wide.");
a2889657
JB
4292 truncate_partial_width_windows = 1;
4293
4294 DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
4295 "*Non-nil means use inverse video for the mode line.");
4296 mode_line_inverse_video = 1;
aa6d10fa
RS
4297
4298 DEFVAR_INT ("line-number-display-limit", &line_number_display_limit,
4299 "*Maximum buffer size for which line number should be displayed.");
4300 line_number_display_limit = 1000000;
fba9ce76
RS
4301
4302 DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
4303 "*Non-nil means highlight region even in nonselected windows.");
4304 highlight_nonselected_windows = 1;
d39b6696
KH
4305
4306 DEFVAR_BOOL ("multiple-frames", &multiple_frames,
3450d04c
KH
4307 "Non-nil if more than one frame is visible on this display.\n\
4308Minibuffer-only frames don't count, but iconified frames do.\n\
4c2eb242
RS
4309This variable is not guaranteed to be accurate except while processing\n\
4310`frame-title-format' and `icon-title-format'.");
d39b6696
KH
4311
4312 DEFVAR_LISP ("frame-title-format", &Vframe_title_format,
4313 "Template for displaying the titlebar of visible frames.\n\
4314\(Assuming the window manager supports this feature.)\n\
4315This variable has the same structure as `mode-line-format' (which see),\n\
4316and is used only on frames for which no explicit name has been set\n\
4317\(see `modify-frame-parameters').");
4318 DEFVAR_LISP ("icon-title-format", &Vicon_title_format,
4319 "Template for displaying the titlebar of an iconified frame.\n\
4320\(Assuming the window manager supports this feature.)\n\
4321This variable has the same structure as `mode-line-format' (which see),\n\
4322and is used only on frames for which no explicit name has been set\n\
4323\(see `modify-frame-parameters').");
4324 Vicon_title_format
4325 = Vframe_title_format
4326 = Fcons (intern ("multiple-frames"),
4327 Fcons (build_string ("%b"),
4328 Fcons (Fcons (build_string (""),
4329 Fcons (intern ("invocation-name"),
4330 Fcons (build_string ("@"),
4331 Fcons (intern ("system-name"),
4332 Qnil)))),
4333 Qnil)));
5992c4f7
KH
4334
4335 DEFVAR_LISP ("message-log-max", &Vmessage_log_max,
4336 "Maximum number of lines to keep in the message log buffer.\n\
4337If nil, disable message logging. If t, log messages but don't truncate\n\
4338the buffer when it becomes large.");
4339 XSETFASTINT (Vmessage_log_max, 50);
08b610e4
RS
4340
4341 DEFVAR_LISP ("window-size-change-functions", &Vwindow_size_change_functions,
4342 "Functions called before redisplay, if window sizes have changed.\n\
4343The value should be a list of functions that take one argument.\n\
4344Just before redisplay, for each frame, if any of its windows have changed\n\
4345size since the last redisplay, or have been split or deleted,\n\
4346all the functions in the list are called, with the frame as argument.");
4347 Vwindow_size_change_functions = Qnil;
75c43375
RS
4348
4349 DEFVAR_LISP ("window-scroll-functions", &Vwindow_scroll_functions,
f908610f 4350 "List of Functions to call before redisplaying a window with scrolling.\n\
75c43375 4351Each function is called with two arguments, the window\n\
8d9583b0
RS
4352and its new display-start position. Note that the value of `window-end'\n\
4353is not valid when these functions are called.");
75c43375 4354 Vwindow_scroll_functions = Qnil;
a2889657
JB
4355}
4356
4357/* initialize the window system */
4358init_xdisp ()
4359{
4360 Lisp_Object root_window;
4361#ifndef COMPILER_REGISTER_BUG
4362 register
4363#endif /* COMPILER_REGISTER_BUG */
4364 struct window *mini_w;
4365
4366 this_line_bufpos = 0;
4367
4368 mini_w = XWINDOW (minibuf_window);
11e82b76 4369 root_window = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (mini_w)));
a2889657
JB
4370
4371 echo_area_glyphs = 0;
4372 previous_echo_glyphs = 0;
4373
4374 if (!noninteractive)
4375 {
44fa5b1e 4376 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (root_window)));
c2213350 4377 XSETFASTINT (XWINDOW (root_window)->top, 0);
44fa5b1e 4378 set_window_height (root_window, FRAME_HEIGHT (f) - 1, 0);
c2213350 4379 XSETFASTINT (mini_w->top, FRAME_HEIGHT (f) - 1);
a2889657
JB
4380 set_window_height (minibuf_window, 1, 0);
4381
c2213350
KH
4382 XSETFASTINT (XWINDOW (root_window)->width, FRAME_WIDTH (f));
4383 XSETFASTINT (mini_w->width, FRAME_WIDTH (f));
a2889657
JB
4384 }
4385}