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