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