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