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