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