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