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