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