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