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