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