(Fdelete_window): Make `frame' a FRAME_PTR and use as such.
[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)
14709f21
JB
953 /* or else vmotion on first line won't work. */
954 && ! NILP (w->start_at_line_beg)
a2889657
JB
955 && ! EQ (w->window_end_valid, Qnil)
956 && do_id && !clip_changed
957 && !blank_end_of_window
44fa5b1e 958 && XFASTINT (w->width) == FRAME_WIDTH (f)
bd66d1ba
RS
959 /* Can't use this case if highlighting a region. */
960 && !(!NILP (Vtransient_mark_mode)
961 && !NILP (current_buffer->mark_active))
962 && NILP (w->region_showing)
a2889657
JB
963 && EQ (last_arrow_position, Voverlay_arrow_position)
964 && EQ (last_arrow_string, Voverlay_arrow_string)
44fa5b1e 965 && (tem = try_window_id (FRAME_SELECTED_WINDOW (f)))
a2889657
JB
966 && tem != -2)
967 {
968 /* tem > 0 means success. tem == -1 means choose new start.
969 tem == -2 means try again with same start,
970 and nothing but whitespace follows the changed stuff.
971 tem == 0 means try again with same start. */
972 if (tem > 0)
973 goto done;
974 }
975 else if (startp >= BEGV && startp <= ZV
976 /* Avoid starting display at end of buffer! */
8de2d90b 977 && (startp < ZV || startp == BEGV
a2889657
JB
978 || (XFASTINT (w->last_modified) >= MODIFF)))
979 {
980 /* Try to redisplay starting at same place as before */
44fa5b1e 981 /* If point has not moved off frame, accept the results */
a2889657
JB
982 try_window (window, startp);
983 if (cursor_vpos >= 0)
aa6d10fa
RS
984 {
985 if (!just_this_one || clip_changed || beg_unchanged < startp)
986 /* Forget any recorded base line for line number display. */
987 w->base_line_number = Qnil;
988 goto done;
989 }
a2889657
JB
990 else
991 cancel_my_columns (w);
992 }
993
994 XFASTINT (w->last_modified) = 0;
995 w->update_mode_line = Qt;
996
997 /* Try to scroll by specified few lines */
998
999 if (scroll_step && !clip_changed)
1000 {
1001 if (point > startp)
1002 {
1003 pos = *vmotion (Z - XFASTINT (w->window_end_pos),
1004 scroll_step, width, hscroll, window);
1005 if (pos.vpos >= height)
1006 goto scroll_fail;
1007 }
1008
1009 pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step,
1010 width, hscroll, window);
1011
1012 if (point >= pos.bufpos)
1013 {
1014 try_window (window, pos.bufpos);
1015 if (cursor_vpos >= 0)
aa6d10fa
RS
1016 {
1017 if (!just_this_one || clip_changed || beg_unchanged < startp)
1018 /* Forget any recorded base line for line number display. */
1019 w->base_line_number = Qnil;
1020 goto done;
1021 }
a2889657
JB
1022 else
1023 cancel_my_columns (w);
1024 }
1025 scroll_fail: ;
1026 }
1027
1028 /* Finally, just choose place to start which centers point */
1029
1030recenter:
aa6d10fa
RS
1031 /* Forget any previously recorded base line for line number display. */
1032 w->base_line_number = Qnil;
1033
a2889657
JB
1034 pos = *vmotion (point, - height / 2, width, hscroll, window);
1035 try_window (window, pos.bufpos);
1036
1037 startp = marker_position (w->start);
1038 w->start_at_line_beg =
1039 (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
1040
1041done:
265a9e55 1042 if ((!NILP (w->update_mode_line)
aa6d10fa
RS
1043 /* If window not full width, must redo its mode line
1044 if the window to its side is being redone */
1045 || (!just_this_one && width < FRAME_WIDTH (f) - 1)
1046 || INTEGERP (w->base_line_pos))
a2889657
JB
1047 && height != XFASTINT (w->height))
1048 display_mode_line (w);
aa6d10fa
RS
1049 if (! line_number_displayed
1050 && ! BUFFERP (w->base_line_pos))
1051 {
1052 w->base_line_pos = Qnil;
1053 w->base_line_number = Qnil;
1054 }
a2889657 1055
7ce2c095
RS
1056 /* When we reach a frame's selected window, redo the frame's menu bar. */
1057 if (!NILP (w->update_mode_line)
1058 && FRAME_MENU_BAR_LINES (f) > 0
1059 && EQ (FRAME_SELECTED_WINDOW (f), window))
1060 display_menu_bar (w);
1061
88f22aff
JB
1062 finish_scroll_bars:
1063 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
30c566e4 1064 {
b1d1124b 1065 int start, end, whole;
30c566e4 1066
b1d1124b 1067 /* Calculate the start and end positions for the current window.
3505ea70
JB
1068 At some point, it would be nice to choose between scrollbars
1069 which reflect the whole buffer size, with special markers
1070 indicating narrowing, and scrollbars which reflect only the
1071 visible region.
1072
b1d1124b
JB
1073 Note that minibuffers sometimes aren't displaying any text. */
1074 if (! MINI_WINDOW_P (w)
1075 || (w == XWINDOW (minibuf_window) && ! echo_area_glyphs))
1076 {
8a9311d7 1077 whole = ZV - BEGV;
6887f623 1078 start = startp - BEGV;
b1d1124b
JB
1079 /* I don't think this is guaranteed to be right. For the
1080 moment, we'll pretend it is. */
8a9311d7 1081 end = (Z - XINT (w->window_end_pos)) - BEGV;
3505ea70
JB
1082
1083 if (end < start) end = start;
8a9311d7 1084 if (whole < (end - start)) whole = end - start;
b1d1124b
JB
1085 }
1086 else
1087 start = end = whole = 0;
30c566e4 1088
88f22aff
JB
1089 /* Indicate what this scroll bar ought to be displaying now. */
1090 (*set_vertical_scroll_bar_hook) (w, end - start, whole, start - 1);
30c566e4 1091
88f22aff 1092 /* Note that we actually used the scroll bar attached to this window,
30c566e4 1093 so it shouldn't be deleted at the end of redisplay. */
88f22aff 1094 (*redeem_scroll_bar_hook) (w);
30c566e4 1095 }
b1d1124b
JB
1096
1097 SET_PT (opoint);
1098 current_buffer = old;
1099 SET_PT (lpoint);
a2889657
JB
1100}
1101\f
1102/* Do full redisplay on one window, starting at position `pos'. */
1103
1104static void
1105try_window (window, pos)
1106 Lisp_Object window;
1107 register int pos;
1108{
1109 register struct window *w = XWINDOW (window);
1110 register int height = window_internal_height (w);
1111 register int vpos = XFASTINT (w->top);
1112 register int last_text_vpos = vpos;
1113 int tab_offset = pos_tab_offset (w, pos);
44fa5b1e 1114 FRAME_PTR f = XFRAME (w->frame);
b1d1124b 1115 int width = window_internal_width (w) - 1;
a2889657
JB
1116 struct position val;
1117
1118 Fset_marker (w->start, make_number (pos), Qnil);
1119 cursor_vpos = -1;
1120 overlay_arrow_seen = 0;
1121 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
1122
1123 while (--height >= 0)
1124 {
1125 val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
1126 tab_offset += width;
1127 if (val.vpos) tab_offset = 0;
1128 vpos++;
1129 if (pos != val.bufpos)
1130 last_text_vpos
1131 /* Next line, unless prev line ended in end of buffer with no cr */
1132 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
1133 pos = val.bufpos;
1134 }
1135
1136 /* If last line is continued in middle of character,
44fa5b1e 1137 include the split character in the text considered on the frame */
a2889657
JB
1138 if (val.hpos < (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
1139 pos++;
1140
44fa5b1e 1141 /* If bottom just moved off end of frame, change mode line percentage. */
a2889657
JB
1142 if (XFASTINT (w->window_end_pos) == 0
1143 && Z != pos)
1144 w->update_mode_line = Qt;
1145
44fa5b1e 1146 /* Say where last char on frame will be, once redisplay is finished. */
a2889657
JB
1147 XFASTINT (w->window_end_pos) = Z - pos;
1148 XFASTINT (w->window_end_vpos) = last_text_vpos - XFASTINT (w->top);
1149 /* But that is not valid info until redisplay finishes. */
1150 w->window_end_valid = Qnil;
1151}
1152\f
1153/* Try to redisplay when buffer is modified locally,
1154 computing insert/delete line to preserve text outside
1155 the bounds of the changes.
1156 Return 1 if successful, 0 if if cannot tell what to do,
1157 or -1 to tell caller to find a new window start,
1158 or -2 to tell caller to do normal redisplay with same window start. */
1159
1160static int
1161try_window_id (window)
1162 Lisp_Object window;
1163{
1164 int pos;
1165 register struct window *w = XWINDOW (window);
1166 register int height = window_internal_height (w);
44fa5b1e 1167 FRAME_PTR f = XFRAME (w->frame);
a2889657
JB
1168 int top = XFASTINT (w->top);
1169 int start = marker_position (w->start);
b1d1124b 1170 int width = window_internal_width (w) - 1;
a2889657
JB
1171 int hscroll = XINT (w->hscroll);
1172 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
1173 register int vpos;
1174 register int i, tem;
1175 int last_text_vpos = 0;
1176 int stop_vpos;
1177
1178 struct position val, bp, ep, xp, pp;
1179 int scroll_amount = 0;
1180 int delta;
1181 int tab_offset, epto;
1182
1183 if (GPT - BEG < beg_unchanged)
1184 beg_unchanged = GPT - BEG;
1185 if (Z - GPT < end_unchanged)
1186 end_unchanged = Z - GPT;
1187
1188 if (beg_unchanged + 1 < start)
1189 return 0; /* Give up if changes go above top of window */
1190
1191 /* Find position before which nothing is changed. */
1192 bp = *compute_motion (start, 0, lmargin,
f7be7f78 1193 beg_unchanged + 1, height + 1, 0, width, hscroll,
a2889657
JB
1194 pos_tab_offset (w, start));
1195 if (bp.vpos >= height)
6e8290aa
JB
1196 {
1197 if (point < bp.bufpos && !bp.contin)
1198 {
44fa5b1e
JB
1199 /* All changes are below the frame, and point is on the frame.
1200 We don't need to change the frame at all.
6e8290aa
JB
1201 But we need to update window_end_pos to account for
1202 any change in buffer size. */
f7be7f78
JB
1203 bp = *compute_motion (start, 0, lmargin,
1204 Z, height, 0,
1205 width, hscroll, pos_tab_offset (w, start));
6e8290aa
JB
1206 XFASTINT (w->window_end_vpos) = height;
1207 XFASTINT (w->window_end_pos) = Z - bp.bufpos;
1208 return 1;
1209 }
1210 return 0;
1211 }
a2889657
JB
1212
1213 vpos = bp.vpos;
1214
44fa5b1e 1215 /* Find beginning of that frame line. Must display from there. */
a2889657
JB
1216 bp = *vmotion (bp.bufpos, 0, width, hscroll, window);
1217
1218 pos = bp.bufpos;
1219 val.hpos = lmargin;
1220 if (pos < start)
1221 return -1;
1222
1223 /* If about to start displaying at the beginning of a continuation line,
44fa5b1e 1224 really start with previous frame line, in case it was not
a2889657 1225 continued when last redisplayed */
05ba02eb
JB
1226 if ((bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0)
1227 ||
1228 /* Likewise if we have to worry about selective display. */
1229 (XTYPE (current_buffer->selective_display) == Lisp_Int
1230 && XINT (current_buffer->selective_display) > 0
1231 && bp.bufpos - 1 == beg_unchanged && vpos > 0))
a2889657
JB
1232 {
1233 bp = *vmotion (bp.bufpos, -1, width, hscroll, window);
1234 --vpos;
1235 pos = bp.bufpos;
1236 }
1237
1238 if (bp.contin && bp.hpos != lmargin)
1239 {
1240 val.hpos = bp.prevhpos - width + lmargin;
1241 pos--;
1242 }
1243
1244 bp.vpos = vpos;
1245
1246 /* Find first visible newline after which no more is changed. */
1247 tem = find_next_newline (Z - max (end_unchanged, Z - ZV), 1);
1248 if (XTYPE (current_buffer->selective_display) == Lisp_Int
1249 && XINT (current_buffer->selective_display) > 0)
1250 while (tem < ZV - 1
1251 && (position_indentation (tem)
1252 >= XINT (current_buffer->selective_display)))
1253 tem = find_next_newline (tem, 1);
1254
1255 /* Compute the cursor position after that newline. */
1256 ep = *compute_motion (pos, vpos, val.hpos, tem,
1257 height, - (1 << (SHORTBITS - 1)),
1258 width, hscroll, pos_tab_offset (w, bp.bufpos));
1259
44fa5b1e
JB
1260 /* If changes reach past the text available on the frame,
1261 just display rest of frame. */
a2889657
JB
1262 if (ep.bufpos > Z - XFASTINT (w->window_end_pos))
1263 stop_vpos = height;
1264 else
1265 stop_vpos = ep.vpos;
1266
1267 /* If no newline before ep, the line ep is on includes some changes
1268 that must be displayed. Make sure we don't stop before it. */
1269 /* Also, if changes reach all the way until ep.bufpos,
1270 it is possible that something was deleted after the
1271 newline before it, so the following line must be redrawn. */
1272 if (stop_vpos == ep.vpos
1273 && (ep.bufpos == BEGV
1274 || FETCH_CHAR (ep.bufpos - 1) != '\n'
1275 || ep.bufpos == Z - end_unchanged))
1276 stop_vpos = ep.vpos + 1;
1277
1278 cursor_vpos = -1;
1279 overlay_arrow_seen = 0;
1280
1281 /* If changes do not reach to bottom of window,
1282 figure out how much to scroll the rest of the window */
1283 if (stop_vpos < height)
1284 {
1285 /* Now determine how far up or down the rest of the window has moved */
1286 epto = pos_tab_offset (w, ep.bufpos);
1287 xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
1288 Z - XFASTINT (w->window_end_pos),
1289 10000, 0, width, hscroll, epto);
1290 scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
1291
44fa5b1e 1292 /* Is everything on frame below the changes whitespace?
a2889657
JB
1293 If so, no scrolling is really necessary. */
1294 for (i = ep.bufpos; i < xp.bufpos; i++)
1295 {
1296 tem = FETCH_CHAR (i);
1297 if (tem != ' ' && tem != '\n' && tem != '\t')
1298 break;
1299 }
1300 if (i == xp.bufpos)
1301 return -2;
1302
1303 XFASTINT (w->window_end_vpos) += scroll_amount;
1304
44fa5b1e 1305 /* Before doing any scrolling, verify that point will be on frame. */
a2889657
JB
1306 if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height))
1307 {
1308 if (point <= xp.bufpos)
1309 {
1310 pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
1311 point, height, - (1 << (SHORTBITS - 1)),
1312 width, hscroll, epto);
1313 }
1314 else
1315 {
1316 pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
1317 point, height, - (1 << (SHORTBITS - 1)),
1318 width, hscroll, pos_tab_offset (w, xp.bufpos));
1319 }
1320 if (pp.bufpos < point || pp.vpos == height)
1321 return 0;
1322 cursor_vpos = pp.vpos + top;
1323 cursor_hpos = pp.hpos + XFASTINT (w->left);
1324 }
1325
1326 if (stop_vpos - scroll_amount >= height
1327 || ep.bufpos == xp.bufpos)
1328 {
1329 if (scroll_amount < 0)
1330 stop_vpos -= scroll_amount;
1331 scroll_amount = 0;
1332 /* In this path, we have altered window_end_vpos
1333 and not left it negative.
1334 We must make sure that, in case display is preempted
44fa5b1e 1335 before the frame changes to reflect what we do here,
a2889657 1336 further updates will not come to try_window_id
44fa5b1e 1337 and assume the frame and window_end_vpos match. */
a2889657
JB
1338 blank_end_of_window = 1;
1339 }
1340 else if (!scroll_amount)
1341 {}
1342 else if (bp.bufpos == Z - end_unchanged)
1343 {
1344 /* If reprinting everything is nearly as fast as scrolling,
1345 don't bother scrolling. Can happen if lines are short. */
44fa5b1e 1346 if (scroll_cost (f, bp.vpos + top - scroll_amount,
a2889657
JB
1347 top + height - max (0, scroll_amount),
1348 scroll_amount)
1349 > xp.bufpos - bp.bufpos - 20)
1350 /* Return "try normal display with same window-start."
1351 Too bad we can't prevent further scroll-thinking. */
1352 return -2;
1353 /* If pure deletion, scroll up as many lines as possible.
1354 In common case of killing a line, this can save the
1355 following line from being overwritten by scrolling
1356 and therefore having to be redrawn. */
44fa5b1e 1357 tem = scroll_frame_lines (f, bp.vpos + top - scroll_amount,
a2889657
JB
1358 top + height - max (0, scroll_amount),
1359 scroll_amount);
1360 if (!tem) stop_vpos = height;
1361 }
1362 else if (scroll_amount)
1363 {
1364 /* If reprinting everything is nearly as fast as scrolling,
1365 don't bother scrolling. Can happen if lines are short. */
1366 /* Note that if scroll_amount > 0, xp.bufpos - bp.bufpos is an
1367 overestimate of cost of reprinting, since xp.bufpos
1368 would end up below the bottom of the window. */
44fa5b1e 1369 if (scroll_cost (f, ep.vpos + top - scroll_amount,
a2889657
JB
1370 top + height - max (0, scroll_amount),
1371 scroll_amount)
1372 > xp.bufpos - ep.bufpos - 20)
1373 /* Return "try normal display with same window-start."
1374 Too bad we can't prevent further scroll-thinking. */
1375 return -2;
44fa5b1e 1376 tem = scroll_frame_lines (f, ep.vpos + top - scroll_amount,
a2889657
JB
1377 top + height - max (0, scroll_amount),
1378 scroll_amount);
1379 if (!tem) stop_vpos = height;
1380 }
1381 }
1382
1383 /* In any case, do not display past bottom of window */
1384 if (stop_vpos >= height)
1385 {
1386 stop_vpos = height;
1387 scroll_amount = 0;
1388 }
1389
1390 /* Handle case where pos is before w->start --
1391 can happen if part of line had been clipped and is not clipped now */
1392 if (vpos == 0 && pos < marker_position (w->start))
1393 Fset_marker (w->start, make_number (pos), Qnil);
1394
1395 /* Redisplay the lines where the text was changed */
1396 last_text_vpos = vpos;
1397 tab_offset = pos_tab_offset (w, pos);
1398 /* If we are starting display in mid-character, correct tab_offset
1399 to account for passing the line that that character really starts in. */
1400 if (val.hpos < lmargin)
1401 tab_offset += width;
1402 while (vpos < stop_vpos)
1403 {
1404 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
1405 tab_offset += width;
1406 if (val.vpos) tab_offset = 0;
1407 if (pos != val.bufpos)
1408 last_text_vpos
1409 /* Next line, unless prev line ended in end of buffer with no cr */
1410 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
1411 pos = val.bufpos;
1412 }
1413
1414 /* There are two cases:
1415 1) we have displayed down to the bottom of the window
1416 2) we have scrolled lines below stop_vpos by scroll_amount */
1417
1418 if (vpos == height)
1419 {
1420 /* If last line is continued in middle of character,
44fa5b1e 1421 include the split character in the text considered on the frame */
a2889657
JB
1422 if (val.hpos < lmargin)
1423 val.bufpos++;
1424 XFASTINT (w->window_end_vpos) = last_text_vpos;
1425 XFASTINT (w->window_end_pos) = Z - val.bufpos;
1426 }
1427
1428 /* If scrolling made blank lines at window bottom,
1429 redisplay to fill those lines */
1430 if (scroll_amount < 0)
1431 {
1432 /* Don't consider these lines for general-purpose scrolling.
1433 That will save time in the scrolling computation. */
44fa5b1e 1434 FRAME_SCROLL_BOTTOM_VPOS (f) = xp.vpos;
a2889657
JB
1435 vpos = xp.vpos;
1436 pos = xp.bufpos;
1437 val.hpos = lmargin;
1438 if (pos == ZV)
1439 vpos = height + scroll_amount;
1440 else if (xp.contin && xp.hpos != lmargin)
1441 {
1442 val.hpos = xp.prevhpos - width + lmargin;
1443 pos--;
1444 }
1445
1446 blank_end_of_window = 1;
1447 tab_offset = pos_tab_offset (w, pos);
1448 /* If we are starting display in mid-character, correct tab_offset
1449 to account for passing the line that that character starts in. */
1450 if (val.hpos < lmargin)
1451 tab_offset += width;
1452
1453 while (vpos < height)
1454 {
1455 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
1456 tab_offset += width;
1457 if (val.vpos) tab_offset = 0;
1458 pos = val.bufpos;
1459 }
1460
1461 /* Here is a case where display_text_line sets cursor_vpos wrong.
1462 Make it be fixed up, below. */
1463 if (xp.bufpos == ZV
1464 && xp.bufpos == point)
1465 cursor_vpos = -1;
1466 }
1467
44fa5b1e 1468 /* If bottom just moved off end of frame, change mode line percentage. */
a2889657
JB
1469 if (XFASTINT (w->window_end_pos) == 0
1470 && Z != val.bufpos)
1471 w->update_mode_line = Qt;
1472
1473 /* Attempt to adjust end-of-text positions to new bottom line */
1474 if (scroll_amount)
1475 {
1476 delta = height - xp.vpos;
1477 if (delta < 0
1478 || (delta > 0 && xp.bufpos <= ZV)
1479 || (delta == 0 && xp.hpos))
1480 {
1481 val = *vmotion (Z - XFASTINT (w->window_end_pos),
1482 delta, width, hscroll, window);
1483 XFASTINT (w->window_end_pos) = Z - val.bufpos;
1484 XFASTINT (w->window_end_vpos) += val.vpos;
1485 }
1486 }
1487
1488 w->window_end_valid = Qnil;
1489
1490 /* If point was not in a line that was displayed, find it */
1491 if (cursor_vpos < 0)
1492 {
1493 val = *compute_motion (start, 0, lmargin, point, 10000, 10000,
1494 width, hscroll, pos_tab_offset (w, start));
44fa5b1e 1495 /* Admit failure if point is off frame now */
a2889657
JB
1496 if (val.vpos >= height)
1497 {
1498 for (vpos = 0; vpos < height; vpos++)
44fa5b1e 1499 cancel_line (vpos + top, f);
a2889657
JB
1500 return 0;
1501 }
1502 cursor_vpos = val.vpos + top;
1503 cursor_hpos = val.hpos + XFASTINT (w->left);
1504 }
1505
44fa5b1e
JB
1506 FRAME_CURSOR_X (f) = max (0, cursor_hpos);
1507 FRAME_CURSOR_Y (f) = cursor_vpos;
a2889657
JB
1508
1509 if (debug_end_pos)
1510 {
1511 val = *compute_motion (start, 0, lmargin, ZV,
1512 height, - (1 << (SHORTBITS - 1)),
1513 width, hscroll, pos_tab_offset (w, start));
1514 if (val.vpos != XFASTINT (w->window_end_vpos))
1515 abort ();
1516 if (XFASTINT (w->window_end_pos)
1517 != Z - val.bufpos)
1518 abort ();
1519 }
1520
1521 return 1;
1522}
1523\f
31b24551
JB
1524/* Mark a section of BUF as modified, but only for the sake of redisplay.
1525 This is useful for recording changes to overlays.
1526
1527 We increment the buffer's modification timestamp and set the
1528 redisplay caches (windows_or_buffers_changed, beg_unchanged, etc)
1529 as if the region of text between START and END had been modified;
1530 the redisplay code will check this against the windows' timestamps,
1531 and redraw the appropriate area of the buffer.
1532
1533 However, if the buffer is unmodified, we bump the last-save
1534 timestamp as well, so that incrementing the timestamp doesn't fool
1535 Emacs into thinking that the buffer's text has been modified.
1536
1537 Tweaking the timestamps shouldn't hurt the first-modification
1538 timestamps recorded in the undo records; those values aren't
1539 written until just before a real text modification is made, so they
1540 will never catch the timestamp value just before this function gets
1541 called. */
1542
1543void
1544redisplay_region (buf, start, end)
1545 struct buffer *buf;
1546 int start, end;
1547{
1548 if (start == end)
1549 return;
1550
1551 if (start > end)
1552 {
1553 int temp = start;
1554 start = end; end = temp;
1555 }
1556
1557 if (buf != current_buffer)
1558 windows_or_buffers_changed = 1;
1559 else
1560 {
1561 if (unchanged_modified == MODIFF)
1562 {
1563 beg_unchanged = start - BEG;
1564 end_unchanged = Z - end;
1565 }
1566 else
1567 {
1568 if (Z - end < end_unchanged)
1569 end_unchanged = Z - end;
1570 if (start - BEG < beg_unchanged)
1571 beg_unchanged = start - BEG;
1572 }
1573 }
1574
1575 /* Increment the buffer's time stamp, but also increment the save
1576 and autosave timestamps, so as not to screw up that timekeeping. */
1577 if (BUF_MODIFF (buf) == buf->save_modified)
1578 buf->save_modified++;
1579 if (BUF_MODIFF (buf) == buf->auto_save_modified)
1580 buf->auto_save_modified++;
1581
1582 BUF_MODIFF (buf) ++;
1583}
1584
1585\f
c581d710 1586/* Copy glyphs from the vector FROM to the rope T.
f7430cb6 1587 But don't actually copy the parts that would come in before S.
c581d710 1588 Value is T, advanced past the copied data. */
a2889657
JB
1589
1590GLYPH *
1c2250c2 1591copy_rope (t, s, from, face)
a2889657
JB
1592 register GLYPH *t; /* Copy to here. */
1593 register GLYPH *s; /* Starting point. */
1c2250c2
JB
1594 Lisp_Object from; /* Data to copy; known to be a vector. */
1595 int face; /* Face to apply to glyphs which don't specify one. */
a2889657 1596{
c581d710
RS
1597 register int n = XVECTOR (from)->size;
1598 register Lisp_Object *f = XVECTOR (from)->contents;
1599
1600 while (n--)
1601 {
1c2250c2
JB
1602 if (t >= s) *t = MAKE_GLYPH (GLYPH_CHAR (*f),
1603 (GLYPH_FACE (*f)
1604 ? GLYPH_FACE (*f)
1605 : face));
c581d710
RS
1606 ++t;
1607 ++f;
1608 }
1609 return t;
1610}
1611
68a37fa8
RS
1612/* Copy exactly LEN glyphs from FROM into data at T.
1613 But don't alter words before S. */
c581d710
RS
1614
1615GLYPH *
1c2250c2 1616copy_part_of_rope (t, s, from, len, face)
c581d710
RS
1617 register GLYPH *t; /* Copy to here. */
1618 register GLYPH *s; /* Starting point. */
1c2250c2 1619 Lisp_Object *from; /* Data to copy. */
c581d710 1620 int len;
1c2250c2 1621 int face; /* Face to apply to glyphs which don't specify one. */
c581d710 1622{
68a37fa8
RS
1623 int n = len;
1624 register Lisp_Object *f = from;
a2889657
JB
1625
1626 while (n--)
1627 {
1c2250c2
JB
1628 if (t >= s) *t = MAKE_GLYPH (GLYPH_CHAR (*f),
1629 (GLYPH_FACE (*f)
1630 ? GLYPH_FACE (*f)
1631 : face));
a2889657
JB
1632 ++t;
1633 ++f;
1634 }
1635 return t;
1636}
1637\f
1638/* Display one line of window w, starting at position START in W's buffer.
1639 Display starting at horizontal position HPOS, which is normally zero
1640 or negative. A negative value causes output up to hpos = 0 to be discarded.
1641 This is done for negative hscroll, or when this is a continuation line
1642 and the continuation occurred in the middle of a multi-column character.
1643
1644 TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
1645
44fa5b1e 1646 Display on position VPOS on the frame. (origin 0).
a2889657
JB
1647
1648 Returns a STRUCT POSITION giving character to start next line with
1649 and where to display it, including a zero or negative hpos.
1650 The vpos field is not really a vpos; it is 1 unless the line is continued */
1651
1652struct position val_display_text_line;
1653
1654static struct position *
1655display_text_line (w, start, vpos, hpos, taboffset)
1656 struct window *w;
1657 int start;
1658 int vpos;
1659 int hpos;
1660 int taboffset;
1661{
1662 register int pos = start;
1663 register int c;
1664 register GLYPH *p1;
1665 int end;
1666 register int pause;
1667 register unsigned char *p;
1668 GLYPH *endp;
1669 register GLYPH *startp;
5fcbb24d 1670 register GLYPH *p1prev = 0;
44fa5b1e 1671 FRAME_PTR f = XFRAME (w->frame);
a2889657 1672 int tab_width = XINT (current_buffer->tab_width);
265a9e55 1673 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
b1d1124b 1674 int width = window_internal_width (w) - 1;
a2889657
JB
1675 struct position val;
1676 int lastpos;
1677 int invis;
1678 int hscroll = XINT (w->hscroll);
1679 int truncate = hscroll
1680 || (truncate_partial_width_windows
44fa5b1e 1681 && XFASTINT (w->width) < FRAME_WIDTH (f))
265a9e55 1682 || !NILP (current_buffer->truncate_lines);
bd66d1ba
RS
1683
1684 /* 1 if we should highlight the region. */
1685 int highlight_region
1686 = !NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active);
1687 int region_beg, region_end;
1688
a2889657
JB
1689 int selective
1690 = XTYPE (current_buffer->selective_display) == Lisp_Int
1691 ? XINT (current_buffer->selective_display)
265a9e55 1692 : !NILP (current_buffer->selective_display) ? -1 : 0;
44fa5b1e 1693 register struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
a2889657 1694 register struct Lisp_Vector *dp = window_display_table (w);
68a37fa8
RS
1695
1696 Lisp_Object default_invis_vector[3];
1697 /* Nonzero means display something where there are invisible lines.
1698 The precise value is the number of glyphs to display. */
a2889657 1699 int selective_rlen
c581d710 1700 = (selective && dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector
68a37fa8
RS
1701 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size
1702 : selective && !NILP (current_buffer->selective_display_ellipses)
1703 ? 3 : 0);
1704 /* This is the sequence of Lisp objects to display
1705 when there are invisible lines. */
1706 Lisp_Object *invis_vector_contents
1707 = (dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector
1708 ? XVECTOR (DISP_INVIS_VECTOR (dp))->contents
1709 : default_invis_vector);
1710
a2889657
JB
1711 GLYPH truncator = (dp == 0 || XTYPE (DISP_TRUNC_GLYPH (dp)) != Lisp_Int
1712 ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
1713 GLYPH continuer = (dp == 0 || XTYPE (DISP_CONTINUE_GLYPH (dp)) != Lisp_Int
1714 ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
1715
31b24551
JB
1716 /* The next buffer location at which the face should change, due
1717 to overlays or text property changes. */
1718 int next_face_change;
1719
1720 /* The face we're currently using. */
1c2250c2 1721 int current_face = 0;
31b24551 1722
68a37fa8
RS
1723 XFASTINT (default_invis_vector[2]) = '.';
1724 default_invis_vector[0] = default_invis_vector[1] = default_invis_vector[2];
1725
a2889657 1726 hpos += XFASTINT (w->left);
44fa5b1e 1727 get_display_line (f, vpos, XFASTINT (w->left));
54ff581a 1728 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
a2889657 1729
bd66d1ba 1730 /* Show where to highlight the region. */
1613b757 1731 if (highlight_region && XMARKER (current_buffer->mark)->buffer != 0
fba9ce76
RS
1732 /* Maybe highlight only in selected window. */
1733 && (highlight_nonselected_windows
6f139a45 1734 || w == XWINDOW (selected_window)))
bd66d1ba
RS
1735 {
1736 region_beg = marker_position (current_buffer->mark);
1737 if (PT < region_beg)
1738 {
1739 region_end = region_beg;
1740 region_beg = PT;
1741 }
1742 else
1743 region_end = PT;
1744 w->region_showing = Qt;
1745 }
1746 else
1747 region_beg = region_end = -1;
1748
a2889657
JB
1749 if (MINI_WINDOW_P (w) && start == 1
1750 && vpos == XFASTINT (w->top))
1751 {
1752 if (minibuf_prompt)
1753 hpos = display_string (w, vpos, minibuf_prompt, hpos,
1754 (!truncate ? continuer : truncator),
1755 -1, -1);
1756 minibuf_prompt_width = hpos;
1757 }
1758
1759 desired_glyphs->bufp[vpos] = pos;
1760 p1 = desired_glyphs->glyphs[vpos] + hpos;
1761 end = ZV;
1762 startp = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
1763 endp = startp + width;
1764
1c2250c2
JB
1765 /* Arrange the overlays nicely for our purposes. Usually, we call
1766 display_text_line on only one line at a time, in which case this
1767 can't really hurt too much, or we call it on lines which appear
1768 one after another in the buffer, in which case all calls to
1769 recenter_overlay_lists but the first will be pretty cheap. */
1770 recenter_overlay_lists (current_buffer, pos);
1771
a2889657
JB
1772 /* Loop generating characters.
1773 Stop at end of buffer, before newline,
31b24551
JB
1774 if reach or pass continuation column,
1775 or at face change. */
a2889657 1776 pause = pos;
31b24551 1777 next_face_change = pos;
a2889657
JB
1778 while (p1 < endp)
1779 {
1780 p1prev = p1;
31b24551 1781 if (pos >= pause)
a2889657 1782 {
31b24551
JB
1783 /* Did we hit the end of the visible region of the buffer?
1784 Stop here. */
1785 if (pos >= end)
a2889657 1786 break;
31b24551
JB
1787
1788 /* Did we reach point? Record the cursor location. */
a2889657
JB
1789 if (pos == point && cursor_vpos < 0)
1790 {
1791 cursor_vpos = vpos;
1792 cursor_hpos = p1 - startp;
1793 }
1794
9dbd4b48 1795#ifdef HAVE_X_WINDOWS
31b24551
JB
1796 /* Did we hit a face change? Figure out what face we should
1797 use now. We also hit this the first time through the
1798 loop, to see what face we should start with. */
a6c87ac8 1799 if (pos == next_face_change && FRAME_X_P (f))
bd66d1ba
RS
1800 current_face = compute_char_face (f, w, pos,
1801 region_beg, region_end,
1802 &next_face_change);
9dbd4b48 1803#endif
31b24551 1804
1c2250c2
JB
1805 pause = end;
1806
1807 if (pos < next_face_change && next_face_change < pause)
1808 pause = next_face_change;
1809
31b24551
JB
1810 /* Wouldn't you hate to read the next line to someone over
1811 the phone? */
a2889657
JB
1812 if (pos < point && point < pause)
1813 pause = point;
1814 if (pos < GPT && GPT < pause)
1815 pause = GPT;
1816
1817 p = &FETCH_CHAR (pos);
1818 }
1819 c = *p++;
1820 if (c >= 040 && c < 0177
c581d710 1821 && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
a2889657
JB
1822 {
1823 if (p1 >= startp)
1c2250c2 1824 *p1 = MAKE_GLYPH (c, current_face);
a2889657
JB
1825 p1++;
1826 }
1827 else if (c == '\n')
1828 {
1829 invis = 0;
1830 while (pos < end
1831 && selective > 0
1832 && position_indentation (pos + 1) >= selective)
1833 {
1834 invis = 1;
1835 pos = find_next_newline (pos + 1, 1);
1836 if (FETCH_CHAR (pos - 1) == '\n')
1837 pos--;
1838 }
1839 if (invis && selective_rlen > 0 && p1 >= startp)
1840 {
1841 p1 += selective_rlen;
1842 if (p1 - startp > width)
1843 p1 = endp;
68a37fa8 1844 copy_part_of_rope (p1prev, p1prev, invis_vector_contents,
1c2250c2 1845 (p1 - p1prev), current_face);
a2889657 1846 }
3c5c35c5
JB
1847#if 1
1848 /* Draw the face of the newline character as extending all the
1849 way to the end of the frame line. */
1850 if (current_face)
1851 while (p1 < endp)
1852 *p1++ = MAKE_GLYPH (' ', current_face);
1853#endif
68a37fa8 1854 break;
a2889657
JB
1855 }
1856 else if (c == '\t')
1857 {
1858 do
1859 {
1860 if (p1 >= startp && p1 < endp)
1c2250c2 1861 *p1 = MAKE_GLYPH (' ', current_face);
a2889657
JB
1862 p1++;
1863 }
1864 while ((p1 - startp + taboffset + hscroll - (hscroll > 0))
1865 % tab_width);
1866 }
6e8290aa 1867 else if (c == Ctl ('M') && selective == -1)
a2889657
JB
1868 {
1869 pos = find_next_newline (pos, 1);
1870 if (FETCH_CHAR (pos - 1) == '\n')
1871 pos--;
1872 if (selective_rlen > 0)
1873 {
1874 p1 += selective_rlen;
1875 if (p1 - startp > width)
1876 p1 = endp;
68a37fa8 1877 copy_part_of_rope (p1prev, p1prev, invis_vector_contents,
1c2250c2 1878 (p1 - p1prev), current_face);
a2889657 1879 }
3c5c35c5
JB
1880#if 1
1881 /* Draw the face of the newline character as extending all the
1882 way to the end of the frame line. */
1883 if (current_face)
1884 while (p1 < endp)
1885 *p1++ = MAKE_GLYPH (' ', current_face);
1886#endif
68a37fa8 1887 break;
a2889657 1888 }
c581d710 1889 else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
a2889657 1890 {
1c2250c2 1891 p1 = copy_rope (p1, startp, DISP_CHAR_VECTOR (dp, c), current_face);
a2889657
JB
1892 }
1893 else if (c < 0200 && ctl_arrow)
1894 {
1895 if (p1 >= startp)
31b24551
JB
1896 *p1 = MAKE_GLYPH ((dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
1897 ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
1c2250c2 1898 current_face);
a2889657 1899 p1++;
6e8290aa 1900 if (p1 >= startp && p1 < endp)
1c2250c2 1901 *p1 = MAKE_GLYPH (c ^ 0100, current_face);
a2889657
JB
1902 p1++;
1903 }
1904 else
1905 {
1906 if (p1 >= startp)
31b24551
JB
1907 *p1 = MAKE_GLYPH ((dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
1908 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
1c2250c2 1909 current_face);
a2889657 1910 p1++;
6e8290aa 1911 if (p1 >= startp && p1 < endp)
1c2250c2 1912 *p1 = MAKE_GLYPH ((c >> 6) + '0', current_face);
a2889657 1913 p1++;
6e8290aa 1914 if (p1 >= startp && p1 < endp)
1c2250c2 1915 *p1 = MAKE_GLYPH ((7 & (c >> 3)) + '0', current_face);
a2889657 1916 p1++;
6e8290aa 1917 if (p1 >= startp && p1 < endp)
1c2250c2 1918 *p1 = MAKE_GLYPH ((7 & c) + '0', current_face);
a2889657
JB
1919 p1++;
1920 }
31b24551 1921
a2889657
JB
1922 pos++;
1923 }
1924
1925 val.hpos = - XINT (w->hscroll);
1926 if (val.hpos)
1927 val.hpos++;
1928
1929 val.vpos = 1;
1930
1931 lastpos = pos;
1932
1933 /* Handle continuation in middle of a character */
1934 /* by backing up over it */
1935 if (p1 > endp)
1936 {
5fcbb24d
JB
1937 /* Don't back up if we never actually displayed any text.
1938 This occurs when the minibuffer prompt takes up the whole line. */
1939 if (p1prev)
1940 {
1941 /* Start the next line with that same character */
1942 pos--;
1943 /* but at negative hpos, to skip the columns output on this line. */
1944 val.hpos += p1prev - endp;
1945 }
1946
a2889657
JB
1947 /* Keep in this line everything up to the continuation column. */
1948 p1 = endp;
1949 }
1950
1951 /* Finish deciding which character to start the next line on,
1952 and what hpos to start it at.
1953 Also set `lastpos' to the last position which counts as "on this line"
1954 for cursor-positioning. */
1955
1956 if (pos < ZV)
1957 {
1958 if (FETCH_CHAR (pos) == '\n')
1959 /* If stopped due to a newline, start next line after it */
1960 pos++;
1961 else
1962 /* Stopped due to right margin of window */
1963 {
1964 if (truncate)
1965 {
1966 *p1++ = truncator;
1967 /* Truncating => start next line after next newline,
1968 and point is on this line if it is before the newline,
1969 and skip none of first char of next line */
1970 pos = find_next_newline (pos, 1);
1971 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
1972
1973 lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
1974 }
1975 else
1976 {
1977 *p1++ = continuer;
1978 val.vpos = 0;
1979 lastpos--;
1980 }
1981 }
1982 }
1983
1984 /* If point is at eol or in invisible text at eol,
44fa5b1e 1985 record its frame location now. */
a2889657
JB
1986
1987 if (start <= point && point <= lastpos && cursor_vpos < 0)
1988 {
1989 cursor_vpos = vpos;
1990 cursor_hpos = p1 - startp;
1991 }
1992
1993 if (cursor_vpos == vpos)
1994 {
1995 if (cursor_hpos < 0) cursor_hpos = 0;
1996 if (cursor_hpos > width) cursor_hpos = width;
1997 cursor_hpos += XFASTINT (w->left);
44fa5b1e 1998 if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
a2889657 1999 {
44fa5b1e
JB
2000 FRAME_CURSOR_Y (f) = cursor_vpos;
2001 FRAME_CURSOR_X (f) = cursor_hpos;
a2889657
JB
2002
2003 if (w == XWINDOW (selected_window))
2004 {
2005 /* Line is not continued and did not start
2006 in middle of character */
2007 if ((hpos - XFASTINT (w->left)
2008 == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
2009 && val.vpos)
2010 {
2011 this_line_bufpos = start;
2012 this_line_buffer = current_buffer;
2013 this_line_vpos = cursor_vpos;
2014 this_line_start_hpos = hpos;
2015 this_line_endpos = Z - lastpos;
2016 }
2017 else
2018 this_line_bufpos = 0;
2019 }
2020 }
2021 }
2022
2023 /* If hscroll and line not empty, insert truncation-at-left marker */
2024 if (hscroll && lastpos != start)
2025 {
2026 *startp = truncator;
2027 if (p1 <= startp)
2028 p1 = startp + 1;
2029 }
2030
44fa5b1e 2031 if (XFASTINT (w->width) + XFASTINT (w->left) != FRAME_WIDTH (f))
a2889657
JB
2032 {
2033 endp++;
2034 if (p1 < startp) p1 = startp;
2035 while (p1 < endp) *p1++ = SPACEGLYPH;
b1d1124b 2036
88f22aff
JB
2037 /* Don't draw vertical bars if we're using scroll bars. They're
2038 covered up by the scroll bars, and it's distracting to see
2039 them when the scroll bar windows are flickering around to be
b1d1124b 2040 reconfigured. */
88f22aff 2041 *p1++ = (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
b1d1124b 2042 ? ' ' : '|');
a2889657
JB
2043 }
2044 desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
2045 p1 - desired_glyphs->glyphs[vpos]);
2046 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
2047
2048 /* If the start of this line is the overlay arrow-position,
2049 then put the arrow string into the display-line. */
2050
2051 if (XTYPE (Voverlay_arrow_position) == Lisp_Marker
2052 && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
2053 && start == marker_position (Voverlay_arrow_position)
2054 && XTYPE (Voverlay_arrow_string) == Lisp_String
2055 && ! overlay_arrow_seen)
2056 {
2057 unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
2058 int i;
2059 int len = XSTRING (Voverlay_arrow_string)->size;
2060
b1d1124b
JB
2061 if (len > width)
2062 len = width;
a2889657
JB
2063 for (i = 0; i < len; i++)
2064 startp[i] = p[i];
2065 if (desired_glyphs->used[vpos] <
2066 (len + startp - desired_glyphs->glyphs[vpos]))
2067 desired_glyphs->used[vpos] = len + startp - desired_glyphs->glyphs[vpos];
2068
2069 overlay_arrow_seen = 1;
2070 }
2071
2072 val.bufpos = pos;
2073 val_display_text_line = val;
2074 return &val_display_text_line;
2075}
2076\f
7ce2c095
RS
2077/* Redisplay the menu bar in the frame for window W. */
2078
2079static void
2080display_menu_bar (w)
2081 struct window *w;
2082{
2083 Lisp_Object items, tail;
2084 register int vpos = 0;
2085 register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2086 int maxendcol = FRAME_WIDTH (f);
2087 int hpos = 0;
2088
2089 if (FRAME_MENU_BAR_LINES (f) <= 0)
2090 return;
2091
2092 get_display_line (f, vpos, 0);
2093
bd66d1ba
RS
2094 /* If the user has switched buffers or windows, we need to
2095 recompute to reflect the new bindings. But we'll
2096 recompute when update_mode_lines is set too; that means
2097 that people can use force-mode-line-update to request
2098 that the menu bar be recomputed. The adverse effect on
2099 the rest of the redisplay algorithm is about the same as
2100 windows_or_buffers_changed anyway. */
2101 if (windows_or_buffers_changed
2102 || update_mode_lines
2103 || (XFASTINT (w->last_modified) < MODIFF
2104 && (XFASTINT (w->last_modified)
2105 <= XBUFFER (w->buffer)->save_modified)))
2106 {
2107 struct buffer *prev = current_buffer;
2108 current_buffer = XBUFFER (w->buffer);
2109 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items ();
2110 current_buffer = prev;
2111 }
2112
2d66ad19 2113 for (tail = FRAME_MENU_BAR_ITEMS (f); CONSP (tail); tail = XCONS (tail)->cdr)
7ce2c095
RS
2114 {
2115 Lisp_Object string;
2d66ad19 2116
7ce2c095
RS
2117 string = XCONS (XCONS (XCONS (tail)->car)->cdr)->car;
2118
2119 /* Record in each item its hpos. */
2120 XFASTINT (XCONS (XCONS (XCONS (tail)->car)->cdr)->cdr) = hpos;
2121
2122 if (hpos < maxendcol)
2123 hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
2124 XSTRING (string)->data,
2d66ad19
RS
2125 hpos, 0, hpos, maxendcol);
2126 /* Put a gap of 3 spaces between items. */
2127 if (hpos < maxendcol)
2128 {
2129 int hpos1 = hpos + 3;
2130 hpos = display_string (w, vpos, "", hpos, 0,
2131 min (hpos1, maxendcol), maxendcol);
2132 }
7ce2c095
RS
2133 }
2134
2135 FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
2136 FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
2d66ad19
RS
2137
2138 /* Fill out the line with spaces. */
2139 if (maxendcol > hpos)
2140 hpos = display_string (w, vpos, "", hpos, 0, maxendcol, -1);
7ce2c095
RS
2141}
2142\f
a2889657
JB
2143/* Display the mode line for window w */
2144
2145static void
2146display_mode_line (w)
2147 struct window *w;
2148{
2149 register int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
2150 register int left = XFASTINT (w->left);
2151 register int right = XFASTINT (w->width) + left;
44fa5b1e 2152 register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
a2889657 2153
aa6d10fa
RS
2154 line_number_displayed = 0;
2155
44fa5b1e 2156 get_display_line (f, vpos, left);
a2889657
JB
2157 display_mode_element (w, vpos, left, 0, right, right,
2158 current_buffer->mode_line_format);
44fa5b1e 2159 FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
a2889657
JB
2160
2161 /* Make the mode line inverse video if the entire line
2162 is made of mode lines.
2163 I.e. if this window is full width,
2164 or if it is the child of a full width window
2165 (which implies that that window is split side-by-side
2166 and the rest of this line is mode lines of the sibling windows). */
44fa5b1e
JB
2167 if (XFASTINT (w->width) == FRAME_WIDTH (f)
2168 || XFASTINT (XWINDOW (w->parent)->width) == FRAME_WIDTH (f))
2169 FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
a2889657
JB
2170
2171#ifdef HAVE_X_WINDOWS
2172 /* I'm trying this out because I saw Unimpress use it, but it's
0956dd96 2173 possible that this may mess adversely with some window managers. -jla
a2889657 2174
0956dd96
JB
2175 Wouldn't it be nice to use something like mode-line-format to
2176 describe frame titles? -JimB */
2177
2178 /* Change the title of the frame to the name of the buffer displayed
2179 in the currently selected window. Don't do this for minibuffer frames,
2180 and don't do it when there's only one non-minibuffer frame. */
22aefb49 2181 if (FRAME_X_P (f)
44fa5b1e 2182 && ! FRAME_MINIBUF_ONLY_P (f)
69ced0fa 2183 && w == XWINDOW (f->selected_window))
0956dd96
JB
2184 x_implicitly_set_name (f, (EQ (Fnext_frame (WINDOW_FRAME (w), Qnil),
2185 WINDOW_FRAME (w))
2186 ? Qnil
2187 : XBUFFER (w->buffer)->name),
11e82b76 2188 Qnil);
a2889657
JB
2189#endif
2190}
2191
2192/* Contribute ELT to the mode line for window W.
2193 How it translates into text depends on its data type.
2194
2195 VPOS is the position of the mode line being displayed.
2196
44fa5b1e 2197 HPOS is the position (absolute on frame) where this element's text
a2889657
JB
2198 should start. The output is truncated automatically at the right
2199 edge of window W.
2200
2201 DEPTH is the depth in recursion. It is used to prevent
2202 infinite recursion here.
2203
2204 MINENDCOL is the hpos before which the element may not end.
2205 The element is padded at the right with spaces if nec
2206 to reach this column.
2207
2208 MAXENDCOL is the hpos past which this element may not extend.
2209 If MINENDCOL is > MAXENDCOL, MINENDCOL takes priority.
2210 (This is necessary to make nested padding and truncation work.)
2211
2212 Returns the hpos of the end of the text generated by ELT.
2213 The next element will receive that value as its HPOS arg,
2214 so as to concatenate the elements. */
2215
2216static int
2217display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
2218 struct window *w;
2219 register int vpos, hpos;
2220 int depth;
2221 int minendcol;
2222 register int maxendcol;
2223 register Lisp_Object elt;
2224{
2225 tail_recurse:
2226 if (depth > 10)
2227 goto invalid;
2228
2229 depth++;
2230
2231#ifdef SWITCH_ENUM_BUG
2232 switch ((int) XTYPE (elt))
2233#else
2234 switch (XTYPE (elt))
2235#endif
2236 {
2237 case Lisp_String:
2238 {
2239 /* A string: output it and check for %-constructs within it. */
2240 register unsigned char c;
2241 register unsigned char *this = XSTRING (elt)->data;
2242
2243 while (hpos < maxendcol && *this)
2244 {
2245 unsigned char *last = this;
2246 while ((c = *this++) != '\0' && c != '%')
2247 ;
2248 if (this - 1 != last)
2249 {
2250 register int lim = --this - last + hpos;
2251 hpos = display_string (w, vpos, last, hpos, 0, hpos,
2252 min (lim, maxendcol));
2253 }
2254 else /* c == '%' */
2255 {
2256 register int spec_width = 0;
2257
2258 /* We can't allow -ve args due to the "%-" construct */
2259 /* Argument specifies minwidth but not maxwidth
2260 (maxwidth can be specified by
2261 (<negative-number> . <stuff>) mode-line elements) */
2262
2263 while ((c = *this++) >= '0' && c <= '9')
2264 {
2265 spec_width = spec_width * 10 + (c - '0');
2266 }
2267
2268 spec_width += hpos;
2269 if (spec_width > maxendcol)
2270 spec_width = maxendcol;
2271
2272 if (c == 'M')
2273 hpos = display_mode_element (w, vpos, hpos, depth,
2274 spec_width, maxendcol,
2275 Vglobal_mode_string);
2276 else if (c != 0)
2277 hpos = display_string (w, vpos,
2278 decode_mode_spec (w, c,
2279 maxendcol - hpos),
2280 hpos, 0, spec_width, maxendcol);
2281 }
2282 }
2283 }
2284 break;
2285
2286 case Lisp_Symbol:
2287 /* A symbol: process the value of the symbol recursively
2288 as if it appeared here directly. Avoid error if symbol void.
2289 Special case: if value of symbol is a string, output the string
2290 literally. */
2291 {
2292 register Lisp_Object tem;
2293 tem = Fboundp (elt);
265a9e55 2294 if (!NILP (tem))
a2889657
JB
2295 {
2296 tem = Fsymbol_value (elt);
2297 /* If value is a string, output that string literally:
2298 don't check for % within it. */
2299 if (XTYPE (tem) == Lisp_String)
2300 hpos = display_string (w, vpos, XSTRING (tem)->data,
2301 hpos, 0, minendcol, maxendcol);
2302 /* Give up right away for nil or t. */
2303 else if (!EQ (tem, elt))
2304 { elt = tem; goto tail_recurse; }
2305 }
2306 }
2307 break;
2308
2309 case Lisp_Cons:
2310 {
2311 register Lisp_Object car, tem;
2312
2313 /* A cons cell: three distinct cases.
2314 If first element is a string or a cons, process all the elements
2315 and effectively concatenate them.
2316 If first element is a negative number, truncate displaying cdr to
2317 at most that many characters. If positive, pad (with spaces)
2318 to at least that many characters.
2319 If first element is a symbol, process the cadr or caddr recursively
2320 according to whether the symbol's value is non-nil or nil. */
2321 car = XCONS (elt)->car;
2322 if (XTYPE (car) == Lisp_Symbol)
2323 {
2324 tem = Fboundp (car);
2325 elt = XCONS (elt)->cdr;
2326 if (XTYPE (elt) != Lisp_Cons)
2327 goto invalid;
2328 /* elt is now the cdr, and we know it is a cons cell.
2329 Use its car if CAR has a non-nil value. */
265a9e55 2330 if (!NILP (tem))
a2889657
JB
2331 {
2332 tem = Fsymbol_value (car);
265a9e55 2333 if (!NILP (tem))
a2889657
JB
2334 { elt = XCONS (elt)->car; goto tail_recurse; }
2335 }
2336 /* Symbol's value is nil (or symbol is unbound)
2337 Get the cddr of the original list
2338 and if possible find the caddr and use that. */
2339 elt = XCONS (elt)->cdr;
265a9e55 2340 if (NILP (elt))
a2889657
JB
2341 break;
2342 else if (XTYPE (elt) != Lisp_Cons)
2343 goto invalid;
2344 elt = XCONS (elt)->car;
2345 goto tail_recurse;
2346 }
2347 else if (XTYPE (car) == Lisp_Int)
2348 {
2349 register int lim = XINT (car);
2350 elt = XCONS (elt)->cdr;
2351 if (lim < 0)
2352 /* Negative int means reduce maximum width.
2353 DO NOT change MINENDCOL here!
2354 (20 -10 . foo) should truncate foo to 10 col
2355 and then pad to 20. */
2356 maxendcol = min (maxendcol, hpos - lim);
2357 else if (lim > 0)
2358 {
2359 /* Padding specified. Don't let it be more than
2360 current maximum. */
2361 lim += hpos;
2362 if (lim > maxendcol)
2363 lim = maxendcol;
2364 /* If that's more padding than already wanted, queue it.
2365 But don't reduce padding already specified even if
2366 that is beyond the current truncation point. */
2367 if (lim > minendcol)
2368 minendcol = lim;
2369 }
2370 goto tail_recurse;
2371 }
2372 else if (XTYPE (car) == Lisp_String || XTYPE (car) == Lisp_Cons)
2373 {
2374 register int limit = 50;
2375 /* LIMIT is to protect against circular lists. */
2376 while (XTYPE (elt) == Lisp_Cons && --limit > 0
2377 && hpos < maxendcol)
2378 {
2379 hpos = display_mode_element (w, vpos, hpos, depth,
2380 hpos, maxendcol,
2381 XCONS (elt)->car);
2382 elt = XCONS (elt)->cdr;
2383 }
2384 }
2385 }
2386 break;
2387
2388 default:
2389 invalid:
2390 return (display_string (w, vpos, "*invalid*", hpos, 0,
2391 minendcol, maxendcol));
2392 }
2393
2394 end:
2395 if (minendcol > hpos)
2396 hpos = display_string (w, vpos, "", hpos, 0, minendcol, -1);
2397 return hpos;
2398}
2399\f
2400/* Return a string for the output of a mode line %-spec for window W,
2401 generated by character C and width MAXWIDTH. */
2402
11e82b76
JB
2403static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
2404
a2889657
JB
2405static char *
2406decode_mode_spec (w, c, maxwidth)
2407 struct window *w;
2408 register char c;
2409 register int maxwidth;
2410{
2411 Lisp_Object obj = Qnil;
44fa5b1e
JB
2412 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2413 char *decode_mode_spec_buf = (char *) FRAME_TEMP_GLYPHS (f)->total_contents;
a2889657 2414
44fa5b1e
JB
2415 if (maxwidth > FRAME_WIDTH (f))
2416 maxwidth = FRAME_WIDTH (f);
a2889657
JB
2417
2418 switch (c)
2419 {
2420 case 'b':
2421 obj = current_buffer->name;
2422#if 0
2423 if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
2424 {
2425 bcopy (XSTRING (obj)->data, decode_mode_spec_buf, maxwidth - 1);
2426 decode_mode_spec_buf[maxwidth - 1] = '\\';
2427 decode_mode_spec_buf[maxwidth] = '\0';
2428 return decode_mode_spec_buf;
2429 }
2430#endif
2431 break;
2432
2433 case 'f':
2434 obj = current_buffer->filename;
2435#if 0
265a9e55 2436 if (NILP (obj))
a2889657
JB
2437 return "[none]";
2438 else if (XTYPE (obj) == Lisp_String && XSTRING (obj)->size > maxwidth)
2439 {
2440 bcopy ("...", decode_mode_spec_buf, 3);
2441 bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
2442 decode_mode_spec_buf + 3, maxwidth - 3);
2443 return decode_mode_spec_buf;
2444 }
2445#endif
2446 break;
2447
aa6d10fa
RS
2448 case 'l':
2449 {
2450 int startpos = marker_position (w->start);
2451 int line, linepos, topline;
2452 int nlines, junk;
2453 Lisp_Object tem;
2454 int height = XFASTINT (w->height);
2455
2456 /* If we decided that this buffer isn't suitable for line numbers,
2457 don't forget that too fast. */
2458 if (EQ (w->base_line_pos, w->buffer))
2459 return "??";
2460
2461 /* If the buffer is very big, don't waste time. */
2462 if (ZV - BEGV > line_number_display_limit)
2463 {
2464 w->base_line_pos = Qnil;
2465 w->base_line_number = Qnil;
2466 return "??";
2467 }
2468
2469 if (!NILP (w->base_line_number)
2470 && !NILP (w->base_line_pos)
2471 && XFASTINT (w->base_line_pos) <= marker_position (w->start))
2472 {
2473 line = XFASTINT (w->base_line_number);
2474 linepos = XFASTINT (w->base_line_pos);
2475 }
2476 else
2477 {
2478 line = 1;
2479 linepos = BEGV;
2480 }
2481
2482 /* Count lines from base line to window start position. */
2483 nlines = display_count_lines (linepos, startpos, startpos, &junk);
2484
2485 topline = nlines + line;
2486
2487 /* Determine a new base line, if the old one is too close
2488 or too far away, or if we did not have one.
2489 "Too close" means it's plausible a scroll-down would
2490 go back past it. */
2491 if (startpos == BEGV)
2492 {
2493 XFASTINT (w->base_line_number) = topline;
2494 XFASTINT (w->base_line_pos) = BEGV;
2495 }
2496 else if (nlines < height + 25 || nlines > height * 3 + 50
2497 || linepos == BEGV)
2498 {
2499 int limit = BEGV;
2500 int position;
2501 int distance = (height * 2 + 30) * 200;
2502
2503 if (startpos - distance > limit)
2504 limit = startpos - distance;
2505
2506 nlines = display_count_lines (startpos, limit,
2507 -(height * 2 + 30),
2508 &position);
2509 /* If we couldn't find the lines we wanted within
2510 200 chars per line,
2511 give up on line numbers for this window. */
2512 if (position == startpos - distance)
2513 {
2514 w->base_line_pos = w->buffer;
2515 w->base_line_number = Qnil;
2516 return "??";
2517 }
2518
2519 XFASTINT (w->base_line_number) = topline - nlines;
2520 XFASTINT (w->base_line_pos) = position;
2521 }
2522
2523 /* Now count lines from the start pos to point. */
2524 nlines = display_count_lines (startpos, PT, PT, &junk);
2525
2526 /* Record that we did display the line number. */
2527 line_number_displayed = 1;
2528
2529 /* Make the string to show. */
2530 sprintf (decode_mode_spec_buf, "%d", topline + nlines);
2531 return decode_mode_spec_buf;
2532 }
2533 break;
2534
a2889657
JB
2535 case 'm':
2536 obj = current_buffer->mode_name;
2537 break;
2538
2539 case 'n':
2540 if (BEGV > BEG || ZV < Z)
2541 return " Narrow";
2542 break;
2543
2544 case '*':
265a9e55 2545 if (!NILP (current_buffer->read_only))
a2889657
JB
2546 return "%";
2547 if (MODIFF > current_buffer->save_modified)
2548 return "*";
2549 return "-";
2550
2551 case 's':
2552 /* status of process */
a2889657 2553 obj = Fget_buffer_process (Fcurrent_buffer ());
265a9e55 2554 if (NILP (obj))
a2889657
JB
2555 return "no process";
2556 obj = Fsymbol_name (Fprocess_status (obj));
2557 break;
a2889657
JB
2558
2559 case 'p':
2560 {
2561 int pos = marker_position (w->start);
2562 int total = ZV - BEGV;
2563
2564 if (XFASTINT (w->window_end_pos) <= Z - ZV)
2565 {
2566 if (pos <= BEGV)
2567 return "All";
2568 else
2569 return "Bottom";
2570 }
2571 else if (pos <= BEGV)
2572 return "Top";
2573 else
2574 {
2575 total = ((pos - BEGV) * 100 + total - 1) / total;
2576 /* We can't normally display a 3-digit number,
2577 so get us a 2-digit number that is close. */
2578 if (total == 100)
2579 total = 99;
2580 sprintf (decode_mode_spec_buf, "%2d%%", total);
2581 return decode_mode_spec_buf;
2582 }
2583 }
2584
2585 case '%':
2586 return "%";
2587
2588 case '[':
2589 {
2590 int i;
2591 char *p;
2592
2593 if (command_loop_level > 5)
2594 return "[[[... ";
2595 p = decode_mode_spec_buf;
2596 for (i = 0; i < command_loop_level; i++)
2597 *p++ = '[';
2598 *p = 0;
2599 return decode_mode_spec_buf;
2600 }
2601
2602 case ']':
2603 {
2604 int i;
2605 char *p;
2606
2607 if (command_loop_level > 5)
2608 return " ...]]]";
2609 p = decode_mode_spec_buf;
2610 for (i = 0; i < command_loop_level; i++)
2611 *p++ = ']';
2612 *p = 0;
2613 return decode_mode_spec_buf;
2614 }
2615
2616 case '-':
2617 {
a2889657
JB
2618 register char *p;
2619 register int i;
2620
2621 if (maxwidth < sizeof (lots_of_dashes))
2622 return lots_of_dashes;
2623 else
2624 {
2625 for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
2626 *p++ = '-';
2627 *p = '\0';
2628 }
2629 return decode_mode_spec_buf;
2630 }
2631 }
2632
2633 if (XTYPE (obj) == Lisp_String)
2634 return (char *) XSTRING (obj)->data;
2635 else
2636 return "";
2637}
aa6d10fa
RS
2638
2639/* Count up to N lines starting from FROM.
2640 But don't go beyond LIMIT.
2641 Return the number of lines thus found (always positive).
2642 Store the position after what was found into *POS_PTR. */
2643
2644static int
2645display_count_lines (from, limit, n, pos_ptr)
2646 int from, limit, n;
2647 int *pos_ptr;
2648{
2649 int oldbegv = BEGV;
2650 int oldzv = ZV;
2651 int shortage = 0;
2652
2653 if (limit < from)
2654 BEGV = limit;
2655 else
2656 ZV = limit;
2657
2658 *pos_ptr = scan_buffer ('\n', from, n, &shortage);
2659
2660 ZV = oldzv;
2661 BEGV = oldbegv;
2662
2663 if (n < 0)
2664 /* When scanning backwards, scan_buffer stops *after* the last newline
2665 it finds, but does count it. Compensate for that. */
2666 return - n - shortage - (*pos_ptr != limit);
2667 return n - shortage;
2668}
a2889657
JB
2669\f
2670/* Display STRING on one line of window W, starting at HPOS.
2671 Display at position VPOS. Caller should have done get_display_line.
11e82b76 2672 If VPOS == -1, display it as the current frame's title.
a2889657
JB
2673
2674 TRUNCATE is GLYPH to display at end if truncated. Zero for none.
2675
2676 MINCOL is the first column ok to end at. (Pad with spaces to this col.)
2677 MAXCOL is the last column ok to end at. Truncate here.
2678 -1 for MINCOL or MAXCOL means no explicit minimum or maximum.
44fa5b1e 2679 Both count from the left edge of the frame, as does HPOS.
a2889657
JB
2680 The right edge of W is an implicit maximum.
2681 If TRUNCATE is nonzero, the implicit maximum is one column before the edge.
2682
2683 Returns ending hpos */
2684
2685static int
2686display_string (w, vpos, string, hpos, truncate, mincol, maxcol)
2687 struct window *w;
2688 unsigned char *string;
2689 int vpos, hpos;
2690 GLYPH truncate;
2691 int mincol, maxcol;
2692{
2693 register int c;
2694 register GLYPH *p1;
2695 int hscroll = XINT (w->hscroll);
253c7d2f 2696 int tab_width = XINT (XBUFFER (w->buffer)->tab_width);
a2889657
JB
2697 register GLYPH *start;
2698 register GLYPH *end;
b1d1124b
JB
2699 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2700 struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
a2889657
JB
2701 GLYPH *p1start = desired_glyphs->glyphs[vpos] + hpos;
2702 int window_width = XFASTINT (w->width);
2703
2704 /* Use the standard display table, not the window's display table.
2705 We don't want the mode line in rot13. */
2706 register struct Lisp_Vector *dp = 0;
2707
2708 if (XTYPE (Vstandard_display_table) == Lisp_Vector
2709 && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
2710 dp = XVECTOR (Vstandard_display_table);
2711
54ff581a 2712 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
a2889657
JB
2713
2714 p1 = p1start;
2715 start = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
2716 end = start + window_width - (truncate != 0);
2717
b1d1124b
JB
2718 if ((window_width + XFASTINT (w->left)) != FRAME_WIDTH (f))
2719 {
88f22aff 2720 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
b1d1124b
JB
2721 {
2722 int i;
2723
88f22aff 2724 for (i = 0; i < VERTICAL_SCROLL_BAR_WIDTH; i++)
b1d1124b
JB
2725 *end-- = ' ';
2726 }
2727 else
2728 *end-- = '|';
2729 }
a2889657
JB
2730
2731 if (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol)
2732 end = desired_glyphs->glyphs[vpos] + maxcol;
2733 if (maxcol >= 0 && mincol > maxcol)
2734 mincol = maxcol;
2735
2736 while (p1 < end)
2737 {
2738 c = *string++;
2739 if (!c) break;
2740 if (c >= 040 && c < 0177
c581d710 2741 && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
a2889657
JB
2742 {
2743 if (p1 >= start)
2744 *p1 = c;
2745 p1++;
2746 }
2747 else if (c == '\t')
2748 {
2749 do
2750 {
2751 if (p1 >= start && p1 < end)
2752 *p1 = SPACEGLYPH;
2753 p1++;
2754 }
2755 while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
2756 }
c581d710 2757 else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
1c2250c2 2758 p1 = copy_rope (p1, start, DISP_CHAR_VECTOR (dp, c), 0);
ded34426 2759 else if (c < 0200 && ! NILP (buffer_defaults.ctl_arrow))
a2889657
JB
2760 {
2761 if (p1 >= start)
2762 *p1 = (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
2763 ? XINT (DISP_CTRL_GLYPH (dp)) : '^');
2764 p1++;
6e8290aa 2765 if (p1 >= start && p1 < end)
a2889657
JB
2766 *p1 = c ^ 0100;
2767 p1++;
2768 }
2769 else
2770 {
2771 if (p1 >= start)
2772 *p1 = (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
2773 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\');
2774 p1++;
6e8290aa 2775 if (p1 >= start && p1 < end)
a2889657
JB
2776 *p1 = (c >> 6) + '0';
2777 p1++;
6e8290aa 2778 if (p1 >= start && p1 < end)
a2889657
JB
2779 *p1 = (7 & (c >> 3)) + '0';
2780 p1++;
6e8290aa 2781 if (p1 >= start && p1 < end)
a2889657
JB
2782 *p1 = (7 & c) + '0';
2783 p1++;
2784 }
2785 }
2786
2787 if (c)
2788 {
2789 p1 = end;
2790 if (truncate) *p1++ = truncate;
2791 }
2792 else if (mincol >= 0)
2793 {
2794 end = desired_glyphs->glyphs[vpos] + mincol;
2795 while (p1 < end)
2796 *p1++ = SPACEGLYPH;
2797 }
2798
2799 {
2800 register int len = p1 - desired_glyphs->glyphs[vpos];
2801
2802 if (len > desired_glyphs->used[vpos])
2803 desired_glyphs->used[vpos] = len;
2804 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
2805
2806 return len;
2807 }
2808}
2809\f
2810void
2811syms_of_xdisp ()
2812{
2813 staticpro (&last_arrow_position);
2814 staticpro (&last_arrow_string);
2815 last_arrow_position = Qnil;
2816 last_arrow_string = Qnil;
2817
2818 DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
8c45d522 2819 "String (or mode line construct) included (normally) in `mode-line-format'.");
a2889657
JB
2820 Vglobal_mode_string = Qnil;
2821
2822 DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
2823 "Marker for where to display an arrow on top of the buffer text.\n\
2824This must be the beginning of a line in order to work.\n\
2825See also `overlay-arrow-string'.");
2826 Voverlay_arrow_position = Qnil;
2827
2828 DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
2829 "String to display as an arrow. See also `overlay-arrow-position'.");
2830 Voverlay_arrow_string = Qnil;
2831
2832 DEFVAR_INT ("scroll-step", &scroll_step,
2833 "*The number of lines to try scrolling a window by when point moves out.\n\
44fa5b1e
JB
2834If that fails to bring point back on frame, point is centered instead.\n\
2835If this is zero, point is always centered after it moves off frame.");
a2889657
JB
2836
2837 DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
2838
2839 DEFVAR_BOOL ("truncate-partial-width-windows",
2840 &truncate_partial_width_windows,
44fa5b1e 2841 "*Non-nil means truncate lines in all windows less than full frame wide.");
a2889657
JB
2842 truncate_partial_width_windows = 1;
2843
2844 DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
2845 "*Non-nil means use inverse video for the mode line.");
2846 mode_line_inverse_video = 1;
aa6d10fa
RS
2847
2848 DEFVAR_INT ("line-number-display-limit", &line_number_display_limit,
2849 "*Maximum buffer size for which line number should be displayed.");
2850 line_number_display_limit = 1000000;
fba9ce76
RS
2851
2852 DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
2853 "*Non-nil means highlight region even in nonselected windows.");
2854 highlight_nonselected_windows = 1;
a2889657
JB
2855}
2856
2857/* initialize the window system */
2858init_xdisp ()
2859{
2860 Lisp_Object root_window;
2861#ifndef COMPILER_REGISTER_BUG
2862 register
2863#endif /* COMPILER_REGISTER_BUG */
2864 struct window *mini_w;
2865
2866 this_line_bufpos = 0;
2867
2868 mini_w = XWINDOW (minibuf_window);
11e82b76 2869 root_window = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (mini_w)));
a2889657
JB
2870
2871 echo_area_glyphs = 0;
2872 previous_echo_glyphs = 0;
2873
2874 if (!noninteractive)
2875 {
44fa5b1e 2876 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (root_window)));
a2889657 2877 XFASTINT (XWINDOW (root_window)->top) = 0;
44fa5b1e
JB
2878 set_window_height (root_window, FRAME_HEIGHT (f) - 1, 0);
2879 XFASTINT (mini_w->top) = FRAME_HEIGHT (f) - 1;
a2889657
JB
2880 set_window_height (minibuf_window, 1, 0);
2881
44fa5b1e
JB
2882 XFASTINT (XWINDOW (root_window)->width) = FRAME_WIDTH (f);
2883 XFASTINT (mini_w->width) = FRAME_WIDTH (f);
a2889657
JB
2884 }
2885}