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