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