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