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