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