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