Merge in octave.el; don't require octave.el.
[emacs.git] / src / xdisp.c
blobdc8b23daff80b2a685d9ee4e2b0cc59cbbccfd33
1 /* Display generation from window structure and buffer text.
2 Copyright (C) 1985, 86, 87, 88, 93, 94, 95 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
22 #include <config.h>
23 #include <stdio.h>
24 /*#include <ctype.h>*/
25 #undef NULL
26 #include "lisp.h"
27 #include "frame.h"
28 #include "window.h"
29 #include "termchar.h"
30 #include "dispextern.h"
31 #include "buffer.h"
32 #include "indent.h"
33 #include "commands.h"
34 #include "macros.h"
35 #include "disptab.h"
36 #include "termhooks.h"
37 #include "intervals.h"
38 #include "keyboard.h"
40 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
41 extern void set_frame_menubar ();
42 extern int pending_menu_activation;
43 #endif
45 extern int interrupt_input;
46 extern int command_loop_level;
48 extern int minibuffer_auto_raise;
50 extern Lisp_Object Qface;
52 extern Lisp_Object Voverriding_local_map;
53 extern Lisp_Object Voverriding_local_map_menu_flag;
55 Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
56 Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
57 Lisp_Object Qredisplay_end_trigger_functions;
59 /* Nonzero means print newline to stdout before next minibuffer message. */
61 int noninteractive_need_newline;
63 /* Nonzero means print newline to message log before next message. */
65 static int message_log_need_newline;
67 #define min(a, b) ((a) < (b) ? (a) : (b))
68 #define max(a, b) ((a) > (b) ? (a) : (b))
69 #define minmax(floor, val, ceil) \
70 ((val) < (floor) ? (floor) : (val) > (ceil) ? (ceil) : (val))
72 /* The buffer position of the first character appearing
73 entirely or partially on the current frame line.
74 Or zero, which disables the optimization for the current frame line. */
75 static int this_line_bufpos;
77 /* Number of characters past the end of this line,
78 including the terminating newline */
79 static int this_line_endpos;
81 /* The vertical position of this frame line. */
82 static int this_line_vpos;
84 /* Hpos value for start of display on this frame line.
85 Usually zero, but negative if first character really began
86 on previous line */
87 static int this_line_start_hpos;
89 /* Buffer that this_line variables are describing. */
90 static struct buffer *this_line_buffer;
92 /* Value of echo_area_glyphs when it was last acted on.
93 If this is nonzero, there is a message on the frame
94 in the minibuffer and it should be erased as soon
95 as it is no longer requested to appear. */
96 char *previous_echo_glyphs;
98 /* Nonzero means truncate lines in all windows less wide than the frame */
99 int truncate_partial_width_windows;
101 /* Nonzero means we have more than one non-minibuffer-only frame.
102 Not guaranteed to be accurate except while parsing frame-title-format. */
103 int multiple_frames;
105 Lisp_Object Vglobal_mode_string;
107 /* Marker for where to display an arrow on top of the buffer text. */
108 Lisp_Object Voverlay_arrow_position;
110 /* String to display for the arrow. */
111 Lisp_Object Voverlay_arrow_string;
113 /* Like mode-line-format, but for the titlebar on a visible frame. */
114 Lisp_Object Vframe_title_format;
116 /* Like mode-line-format, but for the titlebar on an iconified frame. */
117 Lisp_Object Vicon_title_format;
119 /* List of functions to call when a window's size changes. These
120 functions get one arg, a frame on which one or more windows' sizes
121 have changed. */
122 static Lisp_Object Vwindow_size_change_functions;
124 /* Values of those variables at last redisplay. */
125 static Lisp_Object last_arrow_position, last_arrow_string;
127 Lisp_Object Qmenu_bar_update_hook;
129 /* Nonzero if overlay arrow has been displayed once in this window. */
130 static int overlay_arrow_seen;
132 /* Nonzero if visible end of buffer has already been displayed once
133 in this window. (We need this variable in case there are overlay
134 strings that get displayed there.) */
135 static int zv_strings_seen;
137 /* Nonzero means highlight the region even in nonselected windows. */
138 static int highlight_nonselected_windows;
140 /* If cursor motion alone moves point off frame,
141 Try scrolling this many lines up or down if that will bring it back. */
142 static int scroll_step;
144 /* Non-0 means scroll just far enough to bring point back on the screen,
145 when appropriate. */
146 static int scroll_conservatively;
148 /* Recenter the window whenever point gets within this many lines
149 of the top or bottom of the window. */
150 int scroll_margin;
152 /* Nonzero if try_window_id has made blank lines at window bottom
153 since the last redisplay that paused */
154 static int blank_end_of_window;
156 /* Number of windows showing the buffer of the selected window
157 (or another buffer with the same base buffer).
158 keyboard.c refers to this. */
159 int buffer_shared;
161 /* display_text_line sets these to the frame position (origin 0) of point,
162 whether the window is selected or not.
163 Set one to -1 first to determine whether point was found afterwards. */
165 static int cursor_vpos;
166 static int cursor_hpos;
168 static int debug_end_pos;
170 /* Nonzero means display mode line highlighted */
171 int mode_line_inverse_video;
173 static void redisplay_internal ();
174 static int message_log_check_duplicate ();
175 static void echo_area_display ();
176 void mark_window_display_accurate ();
177 static void redisplay_windows ();
178 static void redisplay_window ();
179 static void update_menu_bar ();
180 static void try_window ();
181 static int try_window_id ();
182 static struct position *display_text_line ();
183 static void display_mode_line ();
184 static int display_mode_element ();
185 static char *decode_mode_spec ();
186 static int display_string ();
187 static void display_menu_bar ();
188 static int display_count_lines ();
190 /* Prompt to display in front of the minibuffer contents */
191 Lisp_Object minibuf_prompt;
193 /* Width in columns of current minibuffer prompt. */
194 int minibuf_prompt_width;
196 /* Message to display instead of minibuffer contents
197 This is what the functions error and message make,
198 and command echoing uses it as well.
199 It overrides the minibuf_prompt as well as the buffer. */
200 char *echo_area_glyphs;
202 /* This is the length of the message in echo_area_glyphs. */
203 int echo_area_glyphs_length;
205 /* This is the window where the echo area message was displayed.
206 It is always a minibuffer window, but it may not be the
207 same window currently active as a minibuffer. */
208 Lisp_Object echo_area_window;
210 /* true iff we should redraw the mode lines on the next redisplay */
211 int update_mode_lines;
213 /* Smallest number of characters before the gap
214 at any time since last redisplay that finished.
215 Valid for current buffer when try_window_id can be called. */
216 int beg_unchanged;
218 /* Smallest number of characters after the gap
219 at any time since last redisplay that finished.
220 Valid for current buffer when try_window_id can be called. */
221 int end_unchanged;
223 /* MODIFF as of last redisplay that finished;
224 if it matches MODIFF, and overlay_unchanged_modified
225 matches OVERLAY_MODIFF, that means beg_unchanged and end_unchanged
226 contain no useful information */
227 int unchanged_modified;
229 /* OVERLAY_MODIFF as of last redisplay that finished. */
230 int overlay_unchanged_modified;
232 /* Nonzero if window sizes or contents have changed
233 since last redisplay that finished */
234 int windows_or_buffers_changed;
236 /* Nonzero after display_mode_line if %l was used
237 and it displayed a line number. */
238 int line_number_displayed;
240 /* Maximum buffer size for which to display line numbers. */
241 static int line_number_display_limit;
243 /* Number of lines to keep in the message log buffer.
244 t means infinite. nil means don't log at all. */
245 Lisp_Object Vmessage_log_max;
247 /* Output a newline in the *Messages* buffer if "needs" one. */
249 void
250 message_log_maybe_newline ()
252 if (message_log_need_newline)
253 message_dolog ("", 0, 1);
257 /* Add a string to the message log, optionally terminated with a newline.
258 This function calls low-level routines in order to bypass text property
259 hooks, etc. which might not be safe to run. */
261 void
262 message_dolog (m, len, nlflag)
263 char *m;
264 int len, nlflag;
266 if (!NILP (Vmessage_log_max))
268 struct buffer *oldbuf;
269 int oldpoint, oldbegv, oldzv;
270 int old_windows_or_buffers_changed = windows_or_buffers_changed;
272 oldbuf = current_buffer;
273 Fset_buffer (Fget_buffer_create (build_string ("*Messages*")));
274 current_buffer->undo_list = Qt;
275 oldpoint = PT;
276 oldbegv = BEGV;
277 oldzv = ZV;
278 BEGV = BEG;
279 ZV = Z;
280 if (oldpoint == Z)
281 oldpoint += len + nlflag;
282 if (oldzv == Z)
283 oldzv += len + nlflag;
284 TEMP_SET_PT (Z);
285 if (len)
286 insert_1 (m, len, 1, 0);
287 if (nlflag)
289 int this_bol, prev_bol, dup;
290 insert_1 ("\n", 1, 1, 0);
292 this_bol = scan_buffer ('\n', Z, 0, -2, 0, 0);
293 if (this_bol > BEG)
295 prev_bol = scan_buffer ('\n', this_bol, 0, -2, 0, 0);
296 dup = message_log_check_duplicate (prev_bol, this_bol);
297 if (dup)
299 if (oldpoint > prev_bol)
300 oldpoint -= min (this_bol, oldpoint) - prev_bol;
301 if (oldbegv > prev_bol)
302 oldbegv -= min (this_bol, oldbegv) - prev_bol;
303 if (oldzv > prev_bol)
304 oldzv -= min (this_bol, oldzv) - prev_bol;
305 del_range_1 (prev_bol, this_bol, 0);
306 if (dup > 1)
308 char dupstr[40];
309 int duplen;
311 /* If you change this format, don't forget to also
312 change message_log_check_duplicate. */
313 sprintf (dupstr, " [%d times]", dup);
314 duplen = strlen (dupstr);
315 TEMP_SET_PT (Z-1);
316 if (oldpoint == Z)
317 oldpoint += duplen;
318 if (oldzv == Z)
319 oldzv += duplen;
320 insert_1 (dupstr, duplen, 1, 0);
325 if (NATNUMP (Vmessage_log_max))
327 int pos = scan_buffer ('\n', Z, 0,
328 -XFASTINT (Vmessage_log_max) - 1, 0, 0);
329 oldpoint -= min (pos, oldpoint) - BEG;
330 oldbegv -= min (pos, oldbegv) - BEG;
331 oldzv -= min (pos, oldzv) - BEG;
332 del_range_1 (BEG, pos, 0);
335 BEGV = oldbegv;
336 ZV = oldzv;
337 TEMP_SET_PT (oldpoint);
338 set_buffer_internal (oldbuf);
339 windows_or_buffers_changed = old_windows_or_buffers_changed;
340 message_log_need_newline = !nlflag;
344 /* We are at the end of the buffer after just having inserted a newline.
345 (Note: We depend on the fact we won't be crossing the gap.)
346 Check to see if the most recent message looks a lot like the previous one.
347 Return 0 if different, 1 if the new one should just replace it, or a
348 value N > 1 if we should also append " [N times]". */
350 static int
351 message_log_check_duplicate (prev_bol, this_bol)
352 int prev_bol, this_bol;
354 int i;
355 int len = Z - 1 - this_bol;
356 int seen_dots = 0;
357 unsigned char *p1 = BUF_CHAR_ADDRESS (current_buffer, prev_bol);
358 unsigned char *p2 = BUF_CHAR_ADDRESS (current_buffer, this_bol);
360 for (i = 0; i < len; i++)
362 if (i >= 3 && p1[i-3] == '.' && p1[i-2] == '.' && p1[i-1] == '.'
363 && p1[i] != '\n')
364 seen_dots = 1;
365 if (p1[i] != p2[i])
366 return seen_dots;
368 p1 += len;
369 if (*p1 == '\n')
370 return 2;
371 if (*p1++ == ' ' && *p1++ == '[')
373 int n = 0;
374 while (*p1 >= '0' && *p1 <= '9')
375 n = n * 10 + *p1++ - '0';
376 if (strncmp (p1, " times]\n", 8) == 0)
377 return n+1;
379 return 0;
382 /* Display an echo area message M with a specified length of LEN chars.
383 The string may include null characters. If M is 0, clear out any
384 existing message, and let the minibuffer text show through.
386 The buffer M must continue to exist until after the echo area
387 gets cleared or some other message gets displayed there.
389 Do not pass text that is stored in a Lisp string.
390 Do not pass text in a buffer that was alloca'd. */
392 void
393 message2 (m, len)
394 char *m;
395 int len;
397 /* First flush out any partial line written with print. */
398 message_log_maybe_newline ();
399 if (m)
400 message_dolog (m, len, 1);
401 message2_nolog (m, len);
405 /* The non-logging counterpart of message2. */
407 void
408 message2_nolog (m, len)
409 char *m;
410 int len;
412 if (noninteractive)
414 if (noninteractive_need_newline)
415 putc ('\n', stderr);
416 noninteractive_need_newline = 0;
417 fwrite (m, len, 1, stderr);
418 if (cursor_in_echo_area == 0)
419 fprintf (stderr, "\n");
420 fflush (stderr);
422 /* A null message buffer means that the frame hasn't really been
423 initialized yet. Error messages get reported properly by
424 cmd_error, so this must be just an informative message; toss it. */
425 else if (INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame))
427 Lisp_Object mini_window;
428 FRAME_PTR f;
430 /* Get the frame containing the minibuffer
431 that the selected frame is using. */
432 mini_window = FRAME_MINIBUF_WINDOW (selected_frame);
433 f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
435 FRAME_SAMPLE_VISIBILITY (f);
436 if (FRAME_VISIBLE_P (selected_frame)
437 && ! FRAME_VISIBLE_P (f))
438 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (mini_window)));
440 if (m)
442 echo_area_glyphs = m;
443 echo_area_glyphs_length = len;
445 if (minibuffer_auto_raise)
446 Fraise_frame (WINDOW_FRAME (XWINDOW (mini_window)));
448 else
449 echo_area_glyphs = previous_echo_glyphs = 0;
451 do_pending_window_change ();
452 echo_area_display ();
453 update_frame (f, 1, 1);
454 do_pending_window_change ();
455 if (frame_up_to_date_hook != 0 && ! gc_in_progress)
456 (*frame_up_to_date_hook) (f);
460 /* Display a null-terminated echo area message M. If M is 0, clear out any
461 existing message, and let the minibuffer text show through.
463 The buffer M must continue to exist until after the echo area
464 gets cleared or some other message gets displayed there.
466 Do not pass text that is stored in a Lisp string.
467 Do not pass text in a buffer that was alloca'd. */
469 void
470 message1 (m)
471 char *m;
473 message2 (m, (m ? strlen (m) : 0));
476 void
477 message1_nolog (m)
478 char *m;
480 message2_nolog (m, (m ? strlen (m) : 0));
483 /* Truncate what will be displayed in the echo area
484 the next time we display it--but don't redisplay it now. */
486 void
487 truncate_echo_area (len)
488 int len;
490 /* A null message buffer means that the frame hasn't really been
491 initialized yet. Error messages get reported properly by
492 cmd_error, so this must be just an informative message; toss it. */
493 if (!noninteractive && INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame))
494 echo_area_glyphs_length = len;
497 /* Nonzero if FRAME_MESSAGE_BUF (selected_frame) is being used by print;
498 zero if being used by message. */
499 int message_buf_print;
501 /* Dump an informative message to the minibuf. If M is 0, clear out
502 any existing message, and let the minibuffer text show through. */
504 /* VARARGS 1 */
505 void
506 message (m, a1, a2, a3)
507 char *m;
508 EMACS_INT a1, a2, a3;
510 if (noninteractive)
512 if (m)
514 if (noninteractive_need_newline)
515 putc ('\n', stderr);
516 noninteractive_need_newline = 0;
517 fprintf (stderr, m, a1, a2, a3);
518 if (cursor_in_echo_area == 0)
519 fprintf (stderr, "\n");
520 fflush (stderr);
523 else if (INTERACTIVE)
525 /* The frame whose minibuffer we're going to display the message on.
526 It may be larger than the selected frame, so we need
527 to use its buffer, not the selected frame's buffer. */
528 Lisp_Object mini_window;
529 FRAME_PTR f;
531 /* Get the frame containing the minibuffer
532 that the selected frame is using. */
533 mini_window = FRAME_MINIBUF_WINDOW (selected_frame);
534 f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
536 /* A null message buffer means that the frame hasn't really been
537 initialized yet. Error messages get reported properly by
538 cmd_error, so this must be just an informative message; toss it. */
539 if (FRAME_MESSAGE_BUF (f))
541 if (m)
543 int len;
544 #ifdef NO_ARG_ARRAY
545 EMACS_INT a[3];
546 a[0] = a1;
547 a[1] = a2;
548 a[2] = a3;
550 len = doprnt (FRAME_MESSAGE_BUF (f),
551 (int) FRAME_WIDTH (f), m, (char *)0, 3, a);
552 #else
553 len = doprnt (FRAME_MESSAGE_BUF (f),
554 (int) FRAME_WIDTH (f), m, (char *)0, 3, &a1);
555 #endif /* NO_ARG_ARRAY */
557 message2 (FRAME_MESSAGE_BUF (f), len);
559 else
560 message1 (0);
562 /* Print should start at the beginning of the message
563 buffer next time. */
564 message_buf_print = 0;
569 /* The non-logging version of message. */
570 void
571 message_nolog (m, a1, a2, a3)
572 char *m;
573 EMACS_INT a1, a2, a3;
575 Lisp_Object old_log_max;
576 old_log_max = Vmessage_log_max;
577 Vmessage_log_max = Qnil;
578 message (m, a1, a2, a3);
579 Vmessage_log_max = old_log_max;
582 void
583 update_echo_area ()
585 message2 (echo_area_glyphs, echo_area_glyphs_length);
588 static void
589 echo_area_display ()
591 register int vpos;
592 FRAME_PTR f;
593 Lisp_Object mini_window;
595 /* Choose the minibuffer window for this display.
596 It is the minibuffer window used by the selected frame. */
597 mini_window = FRAME_MINIBUF_WINDOW (selected_frame);
598 /* This is the frame that window is in. */
599 f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
601 if (! FRAME_VISIBLE_P (f))
602 return;
604 if (frame_garbaged)
606 redraw_garbaged_frames ();
607 frame_garbaged = 0;
610 if (echo_area_glyphs || minibuf_level == 0)
612 int i;
614 echo_area_window = mini_window;
616 vpos = XFASTINT (XWINDOW (mini_window)->top);
617 get_display_line (f, vpos, 0);
619 /* Make sure the columns that overlap a left-hand scroll bar
620 are always clear. */
621 for (i = 0; i < FRAME_LEFT_SCROLL_BAR_WIDTH (f); i++)
622 f->desired_glyphs->glyphs[vpos][i] = SPACEGLYPH;
624 display_string (XWINDOW (mini_window), vpos,
625 echo_area_glyphs ? echo_area_glyphs : "",
626 echo_area_glyphs ? echo_area_glyphs_length : -1,
627 FRAME_LEFT_SCROLL_BAR_WIDTH (f),
628 0, 0, 0, FRAME_WIDTH (f));
630 #if 0 /* This just gets in the way. update_frame does the job. */
631 /* If desired cursor location is on this line, put it at end of text */
632 if (cursor_in_echo_area)
633 FRAME_CURSOR_Y (f) = vpos;
634 if (FRAME_CURSOR_Y (f) == vpos)
635 FRAME_CURSOR_X (f) = FRAME_DESIRED_GLYPHS (f)->used[vpos];
636 #endif
638 /* Fill the rest of the minibuffer window with blank lines. */
640 int i;
642 for (i = vpos + 1;
643 i < vpos + XFASTINT (XWINDOW (mini_window)->height); i++)
645 get_display_line (f, i, 0);
646 display_string (XWINDOW (mini_window), vpos,
647 "", 0,
648 FRAME_LEFT_SCROLL_BAR_WIDTH (f),
649 0, 0, 0, FRAME_WIDTH (f));
653 else if (!EQ (mini_window, selected_window))
654 windows_or_buffers_changed++;
656 if (EQ (mini_window, selected_window))
657 this_line_bufpos = 0;
659 previous_echo_glyphs = echo_area_glyphs;
662 /* Update frame titles. */
664 #ifdef HAVE_WINDOW_SYSTEM
665 static char frame_title_buf[512];
666 static char *frame_title_ptr;
668 static int
669 store_frame_title (str, mincol, maxcol)
670 char *str;
671 int mincol, maxcol;
673 char *limit;
674 if (maxcol < 0 || maxcol >= sizeof(frame_title_buf))
675 maxcol = sizeof (frame_title_buf);
676 limit = &frame_title_buf[maxcol];
677 while (*str != '\0' && frame_title_ptr < limit)
678 *frame_title_ptr++ = *str++;
679 while (frame_title_ptr < &frame_title_buf[mincol])
680 *frame_title_ptr++ = ' ';
681 return frame_title_ptr - frame_title_buf;
684 static void
685 x_consider_frame_title (frame)
686 Lisp_Object frame;
688 Lisp_Object fmt;
689 struct buffer *obuf;
690 int len;
691 FRAME_PTR f = XFRAME (frame);
693 if (!(FRAME_WINDOW_P (f) || FRAME_MINIBUF_ONLY_P (f) || f->explicit_name))
694 return;
696 /* Do we have more than one visible frame on this X display? */
698 Lisp_Object tail;
700 for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
702 FRAME_PTR tf = XFRAME (XCONS (tail)->car);
704 if (tf != f && FRAME_KBOARD (tf) == FRAME_KBOARD (f)
705 && !FRAME_MINIBUF_ONLY_P (tf)
706 && (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf)))
707 break;
710 multiple_frames = CONSP (tail);
713 obuf = current_buffer;
714 Fset_buffer (XWINDOW (f->selected_window)->buffer);
715 fmt = (FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format);
716 frame_title_ptr = frame_title_buf;
717 len = display_mode_element (XWINDOW (f->selected_window), 0, 0, 0,
718 0, sizeof (frame_title_buf), fmt);
719 frame_title_ptr = 0;
720 set_buffer_internal (obuf);
721 /* Set the name only if it's changed. This avoids consing
722 in the common case where it hasn't. (If it turns out that we've
723 already wasted too much time by walking through the list with
724 display_mode_element, then we might need to optimize at a higher
725 level than this.) */
726 if (! STRINGP (f->name) || XSTRING (f->name)->size != len
727 || bcmp (frame_title_buf, XSTRING (f->name)->data, len) != 0)
728 x_implicitly_set_name (f, make_string (frame_title_buf, len), Qnil);
730 #else
731 #define frame_title_ptr ((char *)0)
732 #define store_frame_title(str, mincol, maxcol) 0
733 #endif
735 /* Prepare for redisplay by updating menu-bar item lists when appropriate.
736 This can call eval. */
738 void
739 prepare_menu_bars ()
741 register struct window *w = XWINDOW (selected_window);
742 int all_windows;
743 struct gcpro gcpro1, gcpro2;
745 all_windows = (update_mode_lines || buffer_shared > 1
746 || windows_or_buffers_changed);
748 /* Update all frame titles based on their buffer names, etc.
749 We do this before the menu bars so that the buffer-menu
750 will show the up-to-date frame titles.
752 This used to be done after the menu bars, for a reason that
753 was stated as follows but which I do not understand:
754 "We do this after the menu bars so that the frame will first
755 create its menu bar using the name `emacs' if no other name
756 has yet been specified."
757 I think that is no longer a concern. */
758 #ifdef HAVE_WINDOW_SYSTEM
759 if (windows_or_buffers_changed || update_mode_lines)
761 Lisp_Object tail, frame;
763 FOR_EACH_FRAME (tail, frame)
764 if (FRAME_VISIBLE_P (XFRAME (frame))
765 || FRAME_ICONIFIED_P (XFRAME (frame)))
766 x_consider_frame_title (frame);
768 #endif
770 /* Update the menu bar item lists, if appropriate.
771 This has to be done before any actual redisplay
772 or generation of display lines. */
773 if (all_windows)
775 Lisp_Object tail, frame;
776 int count = specpdl_ptr - specpdl;
778 record_unwind_protect (Fstore_match_data, Fmatch_data (Qnil, Qnil));
780 FOR_EACH_FRAME (tail, frame)
782 /* If a window on this frame changed size,
783 report that to the user and clear the size-change flag. */
784 if (FRAME_WINDOW_SIZES_CHANGED (XFRAME (frame)))
786 Lisp_Object functions;
787 /* Clear flag first in case we get error below. */
788 FRAME_WINDOW_SIZES_CHANGED (XFRAME (frame)) = 0;
789 functions = Vwindow_size_change_functions;
790 GCPRO2 (tail, functions);
791 while (CONSP (functions))
793 call1 (XCONS (functions)->car, frame);
794 functions = XCONS (functions)->cdr;
796 UNGCPRO;
798 GCPRO1 (tail);
799 update_menu_bar (XFRAME (frame), 0);
800 UNGCPRO;
803 unbind_to (count, Qnil);
805 else
806 update_menu_bar (selected_frame, 1);
808 /* Motif needs this. See comment in xmenu.c.
809 Turn it off when pending_menu_activation is not defined. */
810 #ifdef USE_X_TOOLKIT
811 pending_menu_activation = 0;
812 #endif
815 /* Do a frame update, taking possible shortcuts into account.
816 This is the main external entry point for redisplay.
818 If the last redisplay displayed an echo area message and that
819 message is no longer requested, we clear the echo area
820 or bring back the minibuffer if that is in use.
822 Do not call eval from within this function.
823 Calls to eval after the call to echo_area_display would confuse
824 the display_line mechanism and would cause a crash.
825 Calls to eval before that point will work most of the time,
826 but can still lose, because this function
827 can be called from signal handlers; with alarms set up;
828 or with synchronous processes running.
830 See Fcall_process; if you called it from here, it could be
831 entered recursively. */
833 static int do_verify_charstarts;
835 /* Counter is used to clear the face cache
836 no more than once ever 1000 redisplays. */
837 static int clear_face_cache_count;
839 /* Record the previous terminal frame we displayed. */
840 static FRAME_PTR previous_terminal_frame;
842 void
843 redisplay ()
845 redisplay_internal (0);
848 /* If PRESERVE_ECHO_AREA is nonzero, it means this redisplay
849 is not in response to any user action; therefore, we should
850 preserve the echo area. (Actually, our caller does that job.)
851 Perhaps in the future avoid recentering windows
852 if it is not necessary; currently that causes some problems. */
854 static void
855 redisplay_internal (preserve_echo_area)
856 int preserve_echo_area;
858 register struct window *w = XWINDOW (selected_window);
859 register int pause;
860 int must_finish = 0;
861 int all_windows;
862 register int tlbufpos, tlendpos;
863 struct position pos;
865 if (noninteractive)
866 return;
868 #ifdef USE_X_TOOLKIT
869 if (popup_activated ())
870 return;
871 #endif
873 if (! FRAME_WINDOW_P (selected_frame)
874 && previous_terminal_frame != selected_frame)
876 /* Since frames on an ASCII terminal share the same display area,
877 displaying a different frame means redisplay the whole thing. */
878 windows_or_buffers_changed++;
879 SET_FRAME_GARBAGED (selected_frame);
880 XSETFRAME (Vterminal_frame, selected_frame);
882 previous_terminal_frame = selected_frame;
884 /* Set the visible flags for all frames.
885 Do this before checking for resized or garbaged frames; they want
886 to know if their frames are visible.
887 See the comment in frame.h for FRAME_SAMPLE_VISIBILITY. */
889 Lisp_Object tail, frame;
891 FOR_EACH_FRAME (tail, frame)
893 FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
895 /* Clear out all the display lines in which we will generate the
896 glyphs to display. */
897 init_desired_glyphs (XFRAME (frame));
901 /* Notice any pending interrupt request to change frame size. */
902 do_pending_window_change ();
904 if (frame_garbaged)
906 redraw_garbaged_frames ();
907 frame_garbaged = 0;
910 prepare_menu_bars ();
912 if (windows_or_buffers_changed)
913 update_mode_lines++;
915 /* Detect case that we need to write or remove a star in the mode line. */
916 if ((SAVE_MODIFF < MODIFF) != !NILP (w->last_had_star))
918 w->update_mode_line = Qt;
919 if (buffer_shared > 1)
920 update_mode_lines++;
923 /* If %c is in use, update it if needed. */
924 if (!NILP (w->column_number_displayed)
925 /* This alternative quickly identifies a common case
926 where no change is needed. */
927 && !(PT == XFASTINT (w->last_point)
928 && XFASTINT (w->last_modified) >= MODIFF
929 && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)
930 && XFASTINT (w->column_number_displayed) != current_column ())
931 w->update_mode_line = Qt;
933 FRAME_SCROLL_BOTTOM_VPOS (XFRAME (w->frame)) = -1;
935 all_windows = update_mode_lines || buffer_shared > 1;
937 /* If specs for an arrow have changed, do thorough redisplay
938 to ensure we remove any arrow that should no longer exist. */
939 if (! EQ (Voverlay_arrow_position, last_arrow_position)
940 || ! EQ (Voverlay_arrow_string, last_arrow_string))
941 all_windows = 1;
943 /* Normally the message* functions will have already displayed and
944 updated the echo area, but the frame may have been trashed, or
945 the update may have been preempted, so display the echo area
946 again here. */
947 if (echo_area_glyphs || previous_echo_glyphs)
949 echo_area_display ();
950 must_finish = 1;
953 /* If showing region, and mark has changed, must redisplay whole window. */
954 if (((!NILP (Vtransient_mark_mode)
955 && !NILP (XBUFFER (w->buffer)->mark_active))
956 != !NILP (w->region_showing))
957 || (!NILP (w->region_showing)
958 && !EQ (w->region_showing,
959 Fmarker_position (XBUFFER (w->buffer)->mark))))
960 this_line_bufpos = -1;
962 tlbufpos = this_line_bufpos;
963 tlendpos = this_line_endpos;
964 if (!all_windows && tlbufpos > 0 && NILP (w->update_mode_line)
965 && !current_buffer->clip_changed
966 && FRAME_VISIBLE_P (XFRAME (w->frame))
967 /* Make sure recorded data applies to current buffer, etc */
968 && this_line_buffer == current_buffer
969 && current_buffer == XBUFFER (w->buffer)
970 && NILP (w->force_start)
971 /* Point must be on the line that we have info recorded about */
972 && PT >= tlbufpos
973 && PT <= Z - tlendpos
974 /* All text outside that line, including its final newline,
975 must be unchanged */
976 && ((XFASTINT (w->last_modified) >= MODIFF
977 && (XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF))
978 || (beg_unchanged >= tlbufpos - 1
979 && GPT >= tlbufpos
980 /* If selective display, can't optimize
981 if the changes start at the beginning of the line. */
982 && ((INTEGERP (current_buffer->selective_display)
983 && XINT (current_buffer->selective_display) > 0
984 ? (beg_unchanged >= tlbufpos
985 && GPT > tlbufpos)
986 : 1))
987 && end_unchanged >= tlendpos
988 && Z - GPT >= tlendpos)))
990 if (tlbufpos > BEGV && FETCH_CHAR (tlbufpos - 1) != '\n'
991 && (tlbufpos == ZV
992 || FETCH_CHAR (tlbufpos) == '\n'))
993 /* Former continuation line has disappeared by becoming empty */
994 goto cancel;
995 else if (XFASTINT (w->last_modified) < MODIFF
996 || XFASTINT (w->last_overlay_modified) < OVERLAY_MODIFF
997 || MINI_WINDOW_P (w))
999 cursor_vpos = -1;
1000 overlay_arrow_seen = 0;
1001 zv_strings_seen = 0;
1002 display_text_line (w, tlbufpos, this_line_vpos, this_line_start_hpos,
1003 pos_tab_offset (w, tlbufpos), 0);
1004 /* If line contains point, is not continued,
1005 and ends at same distance from eob as before, we win */
1006 if (cursor_vpos >= 0 && this_line_bufpos
1007 && this_line_endpos == tlendpos)
1009 /* If this is not the window's last line,
1010 we must adjust the charstarts of the lines below. */
1011 if (this_line_vpos + 1
1012 < XFASTINT (w->top) + window_internal_height (w))
1014 int left = WINDOW_LEFT_MARGIN (w);
1015 int *charstart_next_line
1016 = FRAME_CURRENT_GLYPHS (XFRAME (WINDOW_FRAME (w)))->charstarts[this_line_vpos + 1];
1017 int adjust;
1019 if (Z - tlendpos == ZV)
1020 /* This line ends at end of (accessible part of) buffer.
1021 There is no newline to count. */
1022 adjust = Z - tlendpos - charstart_next_line[left];
1023 else
1024 /* This line ends in a newline.
1025 Must take account of the newline and the rest of the
1026 text that follows. */
1027 adjust = Z - tlendpos + 1 - charstart_next_line[left];
1029 adjust_window_charstarts (w, this_line_vpos, adjust);
1032 if (!WINDOW_FULL_WIDTH_P (w))
1033 preserve_other_columns (w);
1034 goto update;
1036 else
1037 goto cancel;
1039 else if (PT == XFASTINT (w->last_point)
1040 /* Make sure the cursor was last displayed
1041 in this window. Otherwise we have to reposition it. */
1042 && XINT (w->top) <= FRAME_CURSOR_Y (selected_frame)
1043 && (XINT (w->top) + XINT (w->height)
1044 > FRAME_CURSOR_Y (selected_frame)))
1046 if (!must_finish)
1048 do_pending_window_change ();
1049 return;
1051 goto update;
1053 /* If highlighting the region, or if the cursor is in the echo area,
1054 then we can't just move the cursor. */
1055 else if (! (!NILP (Vtransient_mark_mode)
1056 && !NILP (current_buffer->mark_active))
1057 && w == XWINDOW (current_buffer->last_selected_window)
1058 && NILP (w->region_showing)
1059 && !cursor_in_echo_area)
1061 pos = *compute_motion (tlbufpos, 0,
1062 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
1064 PT, 2, - (1 << (BITS_PER_SHORT - 1)),
1065 window_internal_width (w) - 1,
1066 XINT (w->hscroll),
1067 pos_tab_offset (w, tlbufpos), w);
1068 if (pos.vpos < 1)
1070 int width = window_internal_width (w) - 1;
1071 FRAME_CURSOR_X (selected_frame)
1072 = WINDOW_LEFT_MARGIN (w) + minmax (0, pos.hpos, width);
1073 FRAME_CURSOR_Y (selected_frame) = this_line_vpos;
1074 goto update;
1076 else
1077 goto cancel;
1079 cancel:
1080 /* Text changed drastically or point moved off of line */
1081 cancel_line (this_line_vpos, selected_frame);
1084 this_line_bufpos = 0;
1085 all_windows |= buffer_shared > 1;
1087 clear_face_cache_count++;
1089 if (all_windows)
1091 Lisp_Object tail, frame;
1093 #ifdef HAVE_FACES
1094 /* Clear the face cache, only when we do a full redisplay
1095 and not too often either. */
1096 if (clear_face_cache_count > 1000)
1098 clear_face_cache ();
1099 clear_face_cache_count = 0;
1101 #endif
1103 /* Recompute # windows showing selected buffer.
1104 This will be incremented each time such a window is displayed. */
1105 buffer_shared = 0;
1107 FOR_EACH_FRAME (tail, frame)
1109 FRAME_PTR f = XFRAME (frame);
1110 if (FRAME_WINDOW_P (f) || f == selected_frame)
1113 /* Mark all the scroll bars to be removed; we'll redeem the ones
1114 we want when we redisplay their windows. */
1115 if (condemn_scroll_bars_hook)
1116 (*condemn_scroll_bars_hook) (f);
1118 if (FRAME_VISIBLE_P (f))
1119 redisplay_windows (FRAME_ROOT_WINDOW (f), preserve_echo_area);
1121 /* Any scroll bars which redisplay_windows should have nuked
1122 should now go away. */
1123 if (judge_scroll_bars_hook)
1124 (*judge_scroll_bars_hook) (f);
1128 else if (FRAME_VISIBLE_P (selected_frame))
1130 redisplay_window (selected_window, 1, preserve_echo_area);
1131 if (!WINDOW_FULL_WIDTH_P (w))
1132 preserve_other_columns (w);
1135 update:
1136 /* Prevent various kinds of signals during display update.
1137 stdio is not robust about handling signals,
1138 which can cause an apparent I/O error. */
1139 if (interrupt_input)
1140 unrequest_sigio ();
1141 stop_polling ();
1143 if (all_windows)
1145 Lisp_Object tail;
1147 pause = 0;
1149 for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
1151 FRAME_PTR f;
1153 if (!FRAMEP (XCONS (tail)->car))
1154 continue;
1156 f = XFRAME (XCONS (tail)->car);
1158 if ((FRAME_WINDOW_P (f) || f == selected_frame)
1159 && FRAME_VISIBLE_P (f))
1161 pause |= update_frame (f, 0, 0);
1162 if (!pause)
1164 mark_window_display_accurate (f->root_window, 1);
1165 if (frame_up_to_date_hook != 0)
1166 (*frame_up_to_date_hook) (f);
1171 else
1173 if (FRAME_VISIBLE_P (selected_frame))
1174 pause = update_frame (selected_frame, 0, 0);
1175 else
1176 pause = 0;
1178 /* We may have called echo_area_display at the top of this
1179 function. If the echo area is on another frame, that may
1180 have put text on a frame other than the selected one, so the
1181 above call to update_frame would not have caught it. Catch
1182 it here. */
1184 Lisp_Object mini_window;
1185 FRAME_PTR mini_frame;
1187 mini_window = FRAME_MINIBUF_WINDOW (selected_frame);
1188 mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
1190 if (mini_frame != selected_frame && FRAME_WINDOW_P (mini_frame))
1191 pause |= update_frame (mini_frame, 0, 0);
1195 /* If frame does not match, prevent doing single-line-update next time.
1196 Also, don't forget to check every line to update the arrow. */
1197 if (pause)
1199 this_line_bufpos = 0;
1200 if (!NILP (last_arrow_position))
1202 last_arrow_position = Qt;
1203 last_arrow_string = Qt;
1205 /* If we pause after scrolling, some lines in current_frame
1206 may be null, so preserve_other_columns won't be able to
1207 preserve all the vertical-bar separators. So, avoid using it
1208 in that case. */
1209 if (!WINDOW_FULL_WIDTH_P (w))
1210 update_mode_lines = 1;
1213 /* Now text on frame agrees with windows, so
1214 put info into the windows for partial redisplay to follow */
1216 if (!pause)
1218 register struct buffer *b = XBUFFER (w->buffer);
1220 blank_end_of_window = 0;
1221 unchanged_modified = BUF_MODIFF (b);
1222 overlay_unchanged_modified = BUF_OVERLAY_MODIFF (b);
1223 beg_unchanged = BUF_GPT (b) - BUF_BEG (b);
1224 end_unchanged = BUF_Z (b) - BUF_GPT (b);
1226 XSETFASTINT (w->last_point, BUF_PT (b));
1227 XSETFASTINT (w->last_point_x, FRAME_CURSOR_X (selected_frame));
1228 XSETFASTINT (w->last_point_y, FRAME_CURSOR_Y (selected_frame));
1230 if (all_windows)
1231 mark_window_display_accurate (FRAME_ROOT_WINDOW (selected_frame), 1);
1232 else
1234 b->clip_changed = 0;
1235 w->update_mode_line = Qnil;
1236 XSETFASTINT (w->last_modified, BUF_MODIFF (b));
1237 XSETFASTINT (w->last_overlay_modified, BUF_OVERLAY_MODIFF (b));
1238 w->last_had_star
1239 = (BUF_MODIFF (XBUFFER (w->buffer)) > BUF_SAVE_MODIFF (XBUFFER (w->buffer))
1240 ? Qt : Qnil);
1241 w->window_end_valid = w->buffer;
1242 last_arrow_position = Voverlay_arrow_position;
1243 last_arrow_string = Voverlay_arrow_string;
1244 if (do_verify_charstarts)
1245 verify_charstarts (w);
1246 if (frame_up_to_date_hook != 0)
1247 (*frame_up_to_date_hook) (selected_frame);
1249 update_mode_lines = 0;
1250 windows_or_buffers_changed = 0;
1253 /* Start SIGIO interrupts coming again.
1254 Having them off during the code above
1255 makes it less likely one will discard output,
1256 but not impossible, since there might be stuff
1257 in the system buffer here.
1258 But it is much hairier to try to do anything about that. */
1260 if (interrupt_input)
1261 request_sigio ();
1262 start_polling ();
1264 /* Change frame size now if a change is pending. */
1265 do_pending_window_change ();
1267 /* If we just did a pending size change, redisplay again
1268 for the new size. */
1269 if (windows_or_buffers_changed && !pause)
1270 redisplay ();
1273 /* Redisplay, but leave alone any recent echo area message
1274 unless another message has been requested in its place.
1276 This is useful in situations where you need to redisplay but no
1277 user action has occurred, making it inappropriate for the message
1278 area to be cleared. See tracking_off and
1279 wait_reading_process_input for examples of these situations. */
1281 redisplay_preserve_echo_area ()
1283 if (echo_area_glyphs == 0 && previous_echo_glyphs != 0)
1285 echo_area_glyphs = previous_echo_glyphs;
1286 redisplay_internal (1);
1287 echo_area_glyphs = 0;
1289 else
1290 redisplay_internal (1);
1293 void
1294 mark_window_display_accurate (window, flag)
1295 Lisp_Object window;
1296 int flag;
1298 register struct window *w;
1300 for (;!NILP (window); window = w->next)
1302 if (!WINDOWP (window)) abort ();
1303 w = XWINDOW (window);
1305 if (!NILP (w->buffer))
1307 XSETFASTINT (w->last_modified,
1308 !flag ? 0 : BUF_MODIFF (XBUFFER (w->buffer)));
1309 XSETFASTINT (w->last_overlay_modified,
1310 !flag ? 0 : BUF_OVERLAY_MODIFF (XBUFFER (w->buffer)));
1311 w->last_had_star
1312 = (BUF_MODIFF (XBUFFER (w->buffer)) > BUF_SAVE_MODIFF (XBUFFER (w->buffer))
1313 ? Qt : Qnil);
1315 /* Record if we are showing a region, so can make sure to
1316 update it fully at next redisplay. */
1317 w->region_showing = (!NILP (Vtransient_mark_mode)
1318 && w == XWINDOW (current_buffer->last_selected_window)
1319 && !NILP (XBUFFER (w->buffer)->mark_active)
1320 ? Fmarker_position (XBUFFER (w->buffer)->mark)
1321 : Qnil);
1324 w->window_end_valid = w->buffer;
1325 w->update_mode_line = Qnil;
1326 if (!NILP (w->buffer) && flag)
1327 XBUFFER (w->buffer)->clip_changed = 0;
1329 if (!NILP (w->vchild))
1330 mark_window_display_accurate (w->vchild, flag);
1331 if (!NILP (w->hchild))
1332 mark_window_display_accurate (w->hchild, flag);
1335 if (flag)
1337 last_arrow_position = Voverlay_arrow_position;
1338 last_arrow_string = Voverlay_arrow_string;
1340 else
1342 /* t is unequal to any useful value of Voverlay_arrow_... */
1343 last_arrow_position = Qt;
1344 last_arrow_string = Qt;
1348 /* Update the menu bar item list for frame F.
1349 This has to be done before we start to fill in any display lines,
1350 because it can call eval.
1352 If SAVE_MATCH_DATA is 1, we must save and restore it here. */
1354 static void
1355 update_menu_bar (f, save_match_data)
1356 FRAME_PTR f;
1357 int save_match_data;
1359 struct buffer *old = current_buffer;
1360 Lisp_Object window;
1361 register struct window *w;
1363 window = FRAME_SELECTED_WINDOW (f);
1364 w = XWINDOW (window);
1366 if (update_mode_lines)
1367 w->update_mode_line = Qt;
1369 if (FRAME_WINDOW_P (f)
1371 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
1372 FRAME_EXTERNAL_MENU_BAR (f)
1373 #else
1374 FRAME_MENU_BAR_LINES (f) > 0
1375 #endif
1376 : FRAME_MENU_BAR_LINES (f) > 0)
1378 /* If the user has switched buffers or windows, we need to
1379 recompute to reflect the new bindings. But we'll
1380 recompute when update_mode_lines is set too; that means
1381 that people can use force-mode-line-update to request
1382 that the menu bar be recomputed. The adverse effect on
1383 the rest of the redisplay algorithm is about the same as
1384 windows_or_buffers_changed anyway. */
1385 if (windows_or_buffers_changed
1386 || !NILP (w->update_mode_line)
1387 || ((BUF_SAVE_MODIFF (XBUFFER (w->buffer))
1388 < BUF_MODIFF (XBUFFER (w->buffer)))
1389 != !NILP (w->last_had_star))
1390 || ((!NILP (Vtransient_mark_mode)
1391 && !NILP (XBUFFER (w->buffer)->mark_active))
1392 != !NILP (w->region_showing)))
1394 struct buffer *prev = current_buffer;
1395 int count = specpdl_ptr - specpdl;
1397 set_buffer_internal_1 (XBUFFER (w->buffer));
1398 if (save_match_data)
1399 record_unwind_protect (Fstore_match_data, Fmatch_data (Qnil, Qnil));
1400 if (NILP (Voverriding_local_map_menu_flag))
1402 specbind (Qoverriding_terminal_local_map, Qnil);
1403 specbind (Qoverriding_local_map, Qnil);
1406 /* Run the Lucid hook. */
1407 call1 (Vrun_hooks, Qactivate_menubar_hook);
1408 /* If it has changed current-menubar from previous value,
1409 really recompute the menubar from the value. */
1410 if (! NILP (Vlucid_menu_bar_dirty_flag))
1411 call0 (Qrecompute_lucid_menubar);
1412 safe_run_hooks (Qmenu_bar_update_hook);
1413 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1414 /* Redisplay the menu bar in case we changed it. */
1415 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
1416 if (FRAME_WINDOW_P (f))
1417 set_frame_menubar (f, 0, 0);
1418 else
1419 /* On a terminal screen, the menu bar is an ordinary screen
1420 line, and this makes it get updated. */
1421 w->update_mode_line = Qt;
1422 #else /* ! (USE_X_TOOLKIT || HAVE_NTGUI) */
1423 /* In the non-toolkit version, the menu bar is an ordinary screen
1424 line, and this makes it get updated. */
1425 w->update_mode_line = Qt;
1426 #endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI) */
1428 unbind_to (count, Qnil);
1429 set_buffer_internal_1 (prev);
1434 int do_id = 1;
1436 /* Redisplay WINDOW and its subwindows and siblings. */
1438 static void
1439 redisplay_windows (window, preserve_echo_area)
1440 Lisp_Object window;
1441 int preserve_echo_area;
1443 for (; !NILP (window); window = XWINDOW (window)->next)
1444 redisplay_window (window, 0, preserve_echo_area);
1447 /* Redisplay window WINDOW and its subwindows. */
1449 static void
1450 redisplay_window (window, just_this_one, preserve_echo_area)
1451 Lisp_Object window;
1452 int just_this_one, preserve_echo_area;
1454 register struct window *w = XWINDOW (window);
1455 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
1456 int height;
1457 register int lpoint = PT;
1458 struct buffer *old = current_buffer;
1459 register int width = window_internal_width (w) - 1;
1460 register int startp;
1461 register int hscroll = XINT (w->hscroll);
1462 struct position pos;
1463 int opoint = PT;
1464 int tem;
1465 int update_mode_line;
1466 struct Lisp_Char_Table *dp = window_display_table (w);
1468 if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
1470 /* If this is a combination window, do its children; that's all. */
1472 if (!NILP (w->vchild))
1474 redisplay_windows (w->vchild, preserve_echo_area);
1475 return;
1477 if (!NILP (w->hchild))
1479 redisplay_windows (w->hchild, preserve_echo_area);
1480 return;
1482 if (NILP (w->buffer))
1483 abort ();
1485 height = window_internal_height (w);
1486 update_mode_line = (!NILP (w->update_mode_line) || update_mode_lines);
1487 if (XBUFFER (w->buffer)->clip_changed)
1488 update_mode_line = 1;
1490 if (MINI_WINDOW_P (w))
1492 if (w == XWINDOW (echo_area_window) && echo_area_glyphs)
1493 /* We've already displayed the echo area glyphs in this window. */
1494 goto finish_scroll_bars;
1495 else if (w != XWINDOW (minibuf_window))
1497 /* This is a minibuffer, but it's not the currently active one,
1498 so clear it. */
1499 int vpos = XFASTINT (w->top);
1500 int i;
1502 for (i = 0; i < height; i++)
1504 get_display_line (f, vpos + i, 0);
1505 display_string (w, vpos + i, "", 0,
1506 FRAME_LEFT_SCROLL_BAR_WIDTH (f),
1507 0, 1, 0, width);
1510 goto finish_scroll_bars;
1514 /* Otherwise set up data on this window; select its buffer and point value */
1516 if (update_mode_line)
1517 set_buffer_internal_1 (XBUFFER (w->buffer));
1518 else
1519 set_buffer_temp (XBUFFER (w->buffer));
1521 opoint = PT;
1523 /* If %c is in mode line, update it if needed. */
1524 if (!NILP (w->column_number_displayed)
1525 /* This alternative quickly identifies a common case
1526 where no change is needed. */
1527 && !(PT == XFASTINT (w->last_point)
1528 && XFASTINT (w->last_modified) >= MODIFF
1529 && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)
1530 && XFASTINT (w->column_number_displayed) != current_column ())
1531 update_mode_line = 1;
1533 /* Count number of windows showing the selected buffer.
1534 An indirect buffer counts as its base buffer. */
1536 if (!just_this_one)
1538 struct buffer *current_base, *window_base;
1539 current_base = current_buffer;
1540 window_base = XBUFFER (XWINDOW (selected_window)->buffer);
1541 if (current_base->base_buffer)
1542 current_base = current_base->base_buffer;
1543 if (window_base->base_buffer)
1544 window_base = window_base->base_buffer;
1545 if (current_base == window_base)
1546 buffer_shared++;
1549 /* POINT refers normally to the selected window.
1550 For any other window, set up appropriate value. */
1552 if (!EQ (window, selected_window))
1554 int new_pt = marker_position (w->pointm);
1555 if (new_pt < BEGV)
1557 new_pt = BEGV;
1558 Fset_marker (w->pointm, make_number (new_pt), Qnil);
1560 else if (new_pt > (ZV - 1))
1562 new_pt = ZV;
1563 Fset_marker (w->pointm, make_number (new_pt), Qnil);
1565 /* We don't use SET_PT so that the point-motion hooks don't run. */
1566 BUF_PT (current_buffer) = new_pt;
1569 /* If any of the character widths specified in the display table
1570 have changed, invalidate the width run cache. It's true that this
1571 may be a bit late to catch such changes, but the rest of
1572 redisplay goes (non-fatally) haywire when the display table is
1573 changed, so why should we worry about doing any better? */
1574 if (current_buffer->width_run_cache)
1576 struct Lisp_Char_Table *disptab = buffer_display_table ();
1578 if (! disptab_matches_widthtab (disptab,
1579 XVECTOR (current_buffer->width_table)))
1581 invalidate_region_cache (current_buffer,
1582 current_buffer->width_run_cache,
1583 BEG, Z);
1584 recompute_width_table (current_buffer, disptab);
1588 /* If window-start is screwed up, choose a new one. */
1589 if (XMARKER (w->start)->buffer != current_buffer)
1590 goto recenter;
1592 startp = marker_position (w->start);
1594 /* If someone specified a new starting point but did not insist,
1595 check whether it can be used. */
1596 if (!NILP (w->optional_new_start))
1598 w->optional_new_start = Qnil;
1599 /* Check whether this start pos is usable given where point is. */
1601 pos = *compute_motion (startp, 0,
1602 (((EQ (window, minibuf_window)
1603 && startp == BEG)
1604 ? minibuf_prompt_width : 0)
1605 + (hscroll ? 1 - hscroll : 0)),
1607 PT, height, 0,
1608 width, hscroll, pos_tab_offset (w, startp), w);
1609 /* If PT does fit on the screen, we will use this start pos,
1610 so do so by setting force_start. */
1611 if (pos.bufpos == PT)
1612 w->force_start = Qt;
1615 /* Handle case where place to start displaying has been specified,
1616 unless the specified location is outside the accessible range. */
1617 if (!NILP (w->force_start))
1619 w->force_start = Qnil;
1620 /* Forget any recorded base line for line number display. */
1621 w->base_line_number = Qnil;
1622 /* Redisplay the mode line. Select the buffer properly for that.
1623 Also, run the hook window-scroll-functions
1624 because we have scrolled. */
1625 /* Note, we do this after clearing force_start because
1626 if there's an error, it is better to forget about force_start
1627 than to get into an infinite loop calling the hook functions
1628 and having them get more errors. */
1629 if (!update_mode_line
1630 || ! NILP (Vwindow_scroll_functions))
1632 Lisp_Object temp[3];
1634 set_buffer_temp (old);
1635 set_buffer_internal_1 (XBUFFER (w->buffer));
1636 update_mode_line = 1;
1637 w->update_mode_line = Qt;
1638 if (! NILP (Vwindow_scroll_functions))
1640 run_hook_with_args_2 (Qwindow_scroll_functions, window,
1641 make_number (startp));
1642 startp = marker_position (w->start);
1645 XSETFASTINT (w->last_modified, 0);
1646 XSETFASTINT (w->last_overlay_modified, 0);
1647 if (startp < BEGV) startp = BEGV;
1648 if (startp > ZV) startp = ZV;
1649 try_window (window, startp);
1650 if (cursor_vpos < 0)
1652 /* If point does not appear, move point so it does appear */
1653 pos = *compute_motion (startp, 0,
1654 (((EQ (window, minibuf_window)
1655 && startp == BEG)
1656 ? minibuf_prompt_width : 0)
1657 + (hscroll ? 1 - hscroll : 0)),
1659 ZV, height / 2,
1660 - (1 << (BITS_PER_SHORT - 1)),
1661 width, hscroll, pos_tab_offset (w, startp), w);
1662 BUF_PT (current_buffer) = pos.bufpos;
1663 if (w != XWINDOW (selected_window))
1664 Fset_marker (w->pointm, make_number (PT), Qnil);
1665 else
1667 if (current_buffer == old)
1668 lpoint = PT;
1669 FRAME_CURSOR_X (f) = (WINDOW_LEFT_MARGIN (w)
1670 + minmax (0, pos.hpos, width));
1671 FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
1673 /* If we are highlighting the region,
1674 then we just changed the region, so redisplay to show it. */
1675 if (!NILP (Vtransient_mark_mode)
1676 && !NILP (current_buffer->mark_active))
1678 cancel_my_columns (XWINDOW (window));
1679 try_window (window, startp);
1682 goto done;
1685 /* Handle case where text has not changed, only point,
1686 and it has not moved off the frame. */
1688 /* This code is not used for minibuffer for the sake of
1689 the case of redisplaying to replace an echo area message;
1690 since in that case the minibuffer contents per se are usually unchanged.
1691 This code is of no real use in the minibuffer since
1692 the handling of this_line_bufpos, etc.,
1693 in redisplay handles the same cases. */
1695 if (XFASTINT (w->last_modified) >= MODIFF
1696 && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF
1697 && PT >= startp && !current_buffer->clip_changed
1698 && (just_this_one || WINDOW_FULL_WIDTH_P (w))
1699 /* If force-mode-line-update was called, really redisplay;
1700 that's how redisplay is forced after e.g. changing
1701 buffer-invisibility-spec. */
1702 && NILP (w->update_mode_line)
1703 /* Can't use this case if highlighting a region. */
1704 && !(!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
1705 && NILP (w->region_showing)
1706 /* If end pos is out of date, scroll bar and percentage will be wrong */
1707 && INTEGERP (w->window_end_vpos)
1708 && XFASTINT (w->window_end_vpos) < XFASTINT (w->height)
1709 && !EQ (window, minibuf_window))
1711 int this_scroll_margin = scroll_margin;
1713 pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), 0,
1714 PT, height, 0, width, hscroll,
1715 pos_tab_offset (w, startp), w);
1717 /* Don't use a scroll margin that is negative or too large. */
1718 if (this_scroll_margin < 0)
1719 this_scroll_margin = 0;
1721 if (XINT (w->height) < 4 * scroll_margin)
1722 this_scroll_margin = XINT (w->height) / 4;
1724 /* If point fits on the screen, and not within the scroll margin,
1725 we are ok. */
1726 if (pos.vpos < height - this_scroll_margin
1727 && (pos.vpos >= this_scroll_margin || startp == BEGV))
1729 /* Ok, point is still on frame */
1730 if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
1732 /* These variables are supposed to be origin 1 */
1733 FRAME_CURSOR_X (f) = (WINDOW_LEFT_MARGIN (w)
1734 + minmax (0, pos.hpos, width));
1735 FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
1737 /* This doesn't do the trick, because if a window to the right of
1738 this one must be redisplayed, this does nothing because there
1739 is nothing in DesiredFrame yet, and then the other window is
1740 redisplayed, making likes that are empty in this window's columns.
1741 if (WINDOW_FULL_WIDTH_P (w))
1742 preserve_my_columns (w);
1744 goto done;
1746 /* Don't bother trying redisplay with same start;
1747 we already know it will lose */
1749 /* If current starting point was originally the beginning of a line
1750 but no longer is, find a new starting point. */
1751 else if (!NILP (w->start_at_line_beg)
1752 && !(startp <= BEGV
1753 || FETCH_CHAR (startp - 1) == '\n'))
1755 goto recenter;
1757 else if (just_this_one && !MINI_WINDOW_P (w)
1758 && PT >= startp
1759 && XFASTINT (w->last_modified)
1760 /* or else vmotion on first line won't work. */
1761 && ! NILP (w->start_at_line_beg)
1762 && ! EQ (w->window_end_valid, Qnil)
1763 && do_id && !current_buffer->clip_changed
1764 && !blank_end_of_window
1765 && WINDOW_FULL_WIDTH_P (w)
1766 /* Can't use this case if highlighting a region. */
1767 && !(!NILP (Vtransient_mark_mode)
1768 && !NILP (current_buffer->mark_active))
1769 /* Don't use try_window_id if newline
1770 doesn't display as the end of a line. */
1771 && !(dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, '\n')))
1772 && NILP (w->region_showing)
1773 && EQ (last_arrow_position, Voverlay_arrow_position)
1774 && EQ (last_arrow_string, Voverlay_arrow_string)
1775 && (tem = try_window_id (FRAME_SELECTED_WINDOW (f)))
1776 && tem != -2)
1778 /* tem > 0 means success. tem == -1 means choose new start.
1779 tem == -2 means try again with same start,
1780 and nothing but whitespace follows the changed stuff.
1781 tem == 0 means try again with same start. */
1782 if (tem > 0)
1783 goto done;
1785 else if (startp >= BEGV && startp <= ZV
1786 && (startp < ZV
1787 /* Avoid starting at end of buffer. */
1788 #if 0 /* This change causes trouble for M-! finger & RET.
1789 It will have to be considered later. */
1790 || ! EQ (window, selected_window)
1791 /* Don't do the recentering if redisplay
1792 is not for no user action. */
1793 || preserve_echo_area
1794 #endif
1795 || startp == BEGV
1796 || (XFASTINT (w->last_modified) >= MODIFF
1797 && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)))
1799 /* Try to redisplay starting at same place as before */
1800 /* If point has not moved off frame, accept the results */
1801 try_window (window, startp);
1802 if (cursor_vpos >= 0)
1804 if (!just_this_one || current_buffer->clip_changed
1805 || beg_unchanged < startp)
1806 /* Forget any recorded base line for line number display. */
1807 w->base_line_number = Qnil;
1808 goto done;
1810 else
1811 cancel_my_columns (w);
1814 XSETFASTINT (w->last_modified, 0);
1815 XSETFASTINT (w->last_overlay_modified, 0);
1816 /* Redisplay the mode line. Select the buffer properly for that. */
1817 if (!update_mode_line)
1819 set_buffer_temp (old);
1820 set_buffer_internal_1 (XBUFFER (w->buffer));
1821 update_mode_line = 1;
1822 w->update_mode_line = Qt;
1825 /* Try to scroll by specified few lines */
1827 if (scroll_conservatively && !current_buffer->clip_changed
1828 && startp >= BEGV && startp <= ZV)
1830 int this_scroll_margin = scroll_margin;
1832 /* Don't use a scroll margin that is negative or too large. */
1833 if (this_scroll_margin < 0)
1834 this_scroll_margin = 0;
1836 if (XINT (w->height) < 4 * scroll_margin)
1837 this_scroll_margin = XINT (w->height) / 4;
1839 if (PT >= Z - XFASTINT (w->window_end_pos))
1841 struct position pos;
1842 pos = *compute_motion (Z - XFASTINT (w->window_end_pos), 0, 0, 0,
1843 PT, XFASTINT (w->height), 0,
1844 XFASTINT (w->width), XFASTINT (w->hscroll),
1845 pos_tab_offset (w, startp), w);
1846 if (pos.vpos > scroll_conservatively)
1847 goto scroll_fail_1;
1849 pos = *vmotion (startp, pos.vpos + 1 + this_scroll_margin, w);
1851 if (! NILP (Vwindow_scroll_functions))
1853 Fset_marker (w->start, make_number (pos.bufpos), Qnil);
1854 run_hook_with_args_2 (Qwindow_scroll_functions, window,
1855 make_number (pos.bufpos));
1856 pos.bufpos = marker_position (w->start);
1858 try_window (window, pos.bufpos);
1859 if (cursor_vpos >= 0)
1861 if (!just_this_one || current_buffer->clip_changed
1862 || beg_unchanged < startp)
1863 /* Forget any recorded base line for line number display. */
1864 w->base_line_number = Qnil;
1865 goto done;
1867 else
1868 cancel_my_columns (w);
1870 if (PT < startp)
1872 struct position pos;
1873 pos = *compute_motion (PT, 0, 0, 0,
1874 startp, XFASTINT (w->height), 0,
1875 XFASTINT (w->width), XFASTINT (w->hscroll),
1876 pos_tab_offset (w, startp), w);
1877 if (pos.vpos >= scroll_conservatively)
1878 goto scroll_fail_1;
1880 pos = *vmotion (startp, - pos.vpos - this_scroll_margin, w);
1882 if (! NILP (Vwindow_scroll_functions))
1884 Fset_marker (w->start, make_number (pos.bufpos), Qnil);
1885 run_hook_with_args_2 (Qwindow_scroll_functions, window,
1886 make_number (pos.bufpos));
1887 pos.bufpos = marker_position (w->start);
1889 try_window (window, pos.bufpos);
1890 if (cursor_vpos >= 0)
1892 if (!just_this_one || current_buffer->clip_changed
1893 || beg_unchanged < startp)
1894 /* Forget any recorded base line for line number display. */
1895 w->base_line_number = Qnil;
1896 goto done;
1898 else
1899 cancel_my_columns (w);
1901 scroll_fail_1: ;
1904 if (scroll_step && !current_buffer->clip_changed
1905 && startp >= BEGV && startp <= ZV)
1907 if (PT > startp)
1909 pos = *vmotion (Z - XFASTINT (w->window_end_pos), scroll_step, w);
1910 if (pos.vpos >= height)
1911 goto scroll_fail;
1914 pos = *vmotion (startp, (PT < startp ? - scroll_step : scroll_step), w);
1916 if (PT >= pos.bufpos)
1918 if (! NILP (Vwindow_scroll_functions))
1920 Fset_marker (w->start, make_number (pos.bufpos), Qnil);
1921 run_hook_with_args_2 (Qwindow_scroll_functions, window,
1922 make_number (pos.bufpos));
1923 pos.bufpos = marker_position (w->start);
1925 try_window (window, pos.bufpos);
1926 if (cursor_vpos >= 0)
1928 if (!just_this_one || current_buffer->clip_changed
1929 || beg_unchanged < startp)
1930 /* Forget any recorded base line for line number display. */
1931 w->base_line_number = Qnil;
1932 goto done;
1934 else
1935 cancel_my_columns (w);
1937 scroll_fail: ;
1940 /* Finally, just choose place to start which centers point */
1942 recenter:
1943 /* Forget any previously recorded base line for line number display. */
1944 w->base_line_number = Qnil;
1946 pos = *vmotion (PT, - (height / 2), w);
1947 /* Set startp here explicitly in case that helps avoid an infinite loop
1948 in case the window-scroll-functions functions get errors. */
1949 Fset_marker (w->start, make_number (pos.bufpos), Qnil);
1950 if (! NILP (Vwindow_scroll_functions))
1952 run_hook_with_args_2 (Qwindow_scroll_functions, window,
1953 make_number (pos.bufpos));
1954 pos.bufpos = marker_position (w->start);
1956 try_window (window, pos.bufpos);
1958 startp = marker_position (w->start);
1959 w->start_at_line_beg
1960 = (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
1962 done:
1963 if ((update_mode_line
1964 /* If window not full width, must redo its mode line
1965 if the window to its side is being redone */
1966 || (!just_this_one && !WINDOW_FULL_WIDTH_P (w))
1967 || INTEGERP (w->base_line_pos)
1968 || (!NILP (w->column_number_displayed)
1969 && XFASTINT (w->column_number_displayed) != current_column ()))
1970 && height != XFASTINT (w->height))
1971 display_mode_line (w);
1972 if (! line_number_displayed
1973 && ! BUFFERP (w->base_line_pos))
1975 w->base_line_pos = Qnil;
1976 w->base_line_number = Qnil;
1979 /* When we reach a frame's selected window, redo the frame's menu bar. */
1980 if (update_mode_line
1981 && (FRAME_WINDOW_P (f)
1983 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
1984 FRAME_EXTERNAL_MENU_BAR (f)
1985 #else
1986 FRAME_MENU_BAR_LINES (f) > 0
1987 #endif
1988 : FRAME_MENU_BAR_LINES (f) > 0)
1989 && EQ (FRAME_SELECTED_WINDOW (f), window))
1990 display_menu_bar (w);
1992 finish_scroll_bars:
1993 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
1995 int start, end, whole;
1997 /* Calculate the start and end positions for the current window.
1998 At some point, it would be nice to choose between scrollbars
1999 which reflect the whole buffer size, with special markers
2000 indicating narrowing, and scrollbars which reflect only the
2001 visible region.
2003 Note that minibuffers sometimes aren't displaying any text. */
2004 if (! MINI_WINDOW_P (w)
2005 || (w == XWINDOW (minibuf_window) && ! echo_area_glyphs))
2007 whole = ZV - BEGV;
2008 start = marker_position (w->start) - BEGV;
2009 /* I don't think this is guaranteed to be right. For the
2010 moment, we'll pretend it is. */
2011 end = (Z - XINT (w->window_end_pos)) - BEGV;
2013 if (end < start) end = start;
2014 if (whole < (end - start)) whole = end - start;
2016 else
2017 start = end = whole = 0;
2019 /* Indicate what this scroll bar ought to be displaying now. */
2020 (*set_vertical_scroll_bar_hook) (w, end - start, whole, start);
2022 /* Note that we actually used the scroll bar attached to this window,
2023 so it shouldn't be deleted at the end of redisplay. */
2024 (*redeem_scroll_bar_hook) (w);
2027 BUF_PT (current_buffer) = opoint;
2028 if (update_mode_line)
2029 set_buffer_internal_1 (old);
2030 else
2031 set_buffer_temp (old);
2032 BUF_PT (current_buffer) = lpoint;
2035 /* Do full redisplay on one window, starting at position `pos'. */
2037 static void
2038 try_window (window, pos)
2039 Lisp_Object window;
2040 register int pos;
2042 register struct window *w = XWINDOW (window);
2043 register int height = window_internal_height (w);
2044 register int vpos = XFASTINT (w->top);
2045 register int last_text_vpos = vpos;
2046 int tab_offset = pos_tab_offset (w, pos);
2047 FRAME_PTR f = XFRAME (w->frame);
2048 int width = window_internal_width (w) - 1;
2049 struct position val;
2051 /* POS should never be out of range! */
2052 if (pos < XBUFFER (w->buffer)->begv
2053 || pos > XBUFFER (w->buffer)->zv)
2054 abort ();
2056 Fset_marker (w->start, make_number (pos), Qnil);
2057 cursor_vpos = -1;
2058 overlay_arrow_seen = 0;
2059 zv_strings_seen = 0;
2060 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
2061 val.ovstring_chars_done = 0;
2063 while (--height >= 0)
2065 val = *display_text_line (w, pos, vpos, val.hpos, tab_offset,
2066 val.ovstring_chars_done);
2067 tab_offset += width;
2068 /* For the first line displayed, display_text_line
2069 subtracts the prompt width from the tab offset.
2070 But it does not affect the value of our variable tab_offset.
2071 So we do the subtraction again,
2072 for the sake of continuation lines of that first line. */
2073 if (MINI_WINDOW_P (w) && vpos == XFASTINT (w->top))
2074 tab_offset -= minibuf_prompt_width;
2076 if (val.vpos) tab_offset = 0;
2077 vpos++;
2078 if (pos != val.bufpos)
2080 int invis = 0;
2081 #ifdef USE_TEXT_PROPERTIES
2082 Lisp_Object invis_prop;
2083 invis_prop = Fget_char_property (val.bufpos-1, Qinvisible, window);
2084 invis = TEXT_PROP_MEANS_INVISIBLE (invis_prop);
2085 #endif
2087 last_text_vpos
2088 /* Next line, unless prev line ended in end of buffer with no cr */
2089 = vpos - (val.vpos
2090 && (FETCH_CHAR (val.bufpos - 1) != '\n' || invis));
2092 pos = val.bufpos;
2095 /* If last line is continued in middle of character,
2096 include the split character in the text considered on the frame */
2097 if (val.hpos < (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
2098 pos++;
2100 /* If bottom just moved off end of frame, change mode line percentage. */
2101 if (XFASTINT (w->window_end_pos) == 0
2102 && Z != pos)
2103 w->update_mode_line = Qt;
2105 /* Say where last char on frame will be, once redisplay is finished. */
2106 XSETFASTINT (w->window_end_pos, Z - pos);
2107 XSETFASTINT (w->window_end_vpos, last_text_vpos - XFASTINT (w->top));
2108 /* But that is not valid info until redisplay finishes. */
2109 w->window_end_valid = Qnil;
2112 /* Try to redisplay when buffer is modified locally,
2113 computing insert/delete line to preserve text outside
2114 the bounds of the changes.
2115 Return 1 if successful, 0 if if cannot tell what to do,
2116 or -1 to tell caller to find a new window start,
2117 or -2 to tell caller to do normal redisplay with same window start. */
2119 static int
2120 try_window_id (window)
2121 Lisp_Object window;
2123 int pos;
2124 register struct window *w = XWINDOW (window);
2125 register int height = window_internal_height (w);
2126 FRAME_PTR f = XFRAME (w->frame);
2127 int top = XFASTINT (w->top);
2128 int start = marker_position (w->start);
2129 int width = window_internal_width (w) - 1;
2130 int hscroll = XINT (w->hscroll);
2131 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
2132 int did_motion;
2133 register int vpos;
2134 register int i, tem;
2135 int last_text_vpos = 0;
2136 int stop_vpos;
2137 int selective = (INTEGERP (current_buffer->selective_display)
2138 ? XINT (current_buffer->selective_display)
2139 : !NILP (current_buffer->selective_display) ? -1 : 0);
2141 struct position val, bp, ep, xp, pp;
2142 int scroll_amount = 0;
2143 int delta;
2144 int tab_offset, epto, old_tick;
2146 if (GPT - BEG < beg_unchanged)
2147 beg_unchanged = GPT - BEG;
2148 if (Z - GPT < end_unchanged)
2149 end_unchanged = Z - GPT;
2151 if (beg_unchanged + BEG < start)
2152 return 0; /* Give up if changes go above top of window */
2154 /* Find position before which nothing is changed. */
2155 bp = *compute_motion (start, 0, lmargin, 0,
2156 min (ZV, beg_unchanged + BEG), height, 0,
2157 width, hscroll, pos_tab_offset (w, start), w);
2158 if (bp.vpos >= height)
2160 if (PT < bp.bufpos)
2162 /* All changes are beyond the window end, and point is on the screen.
2163 We don't need to change the text at all.
2164 But we need to update window_end_pos to account for
2165 any change in buffer size. */
2166 bp = *compute_motion (start, 0, lmargin, 0,
2167 ZV, height, 0,
2168 width, hscroll, pos_tab_offset (w, start), w);
2169 XSETFASTINT (w->window_end_vpos, height);
2170 XSETFASTINT (w->window_end_pos, Z - bp.bufpos);
2171 goto findpoint;
2173 return 0;
2176 vpos = bp.vpos;
2178 /* Find beginning of that frame line. Must display from there. */
2179 bp = *vmotion (bp.bufpos, 0, w);
2181 pos = bp.bufpos;
2182 val.hpos = lmargin;
2183 if (pos < start)
2184 return -1;
2186 did_motion = 0;
2187 /* If about to start displaying at the beginning of a continuation line,
2188 really start with previous frame line, in case it was not
2189 continued when last redisplayed */
2190 if ((bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0)
2192 /* Likewise if we have to worry about selective display. */
2193 (selective > 0 && bp.bufpos - 1 == beg_unchanged && vpos > 0))
2195 bp = *vmotion (bp.bufpos, -1, w);
2196 --vpos;
2197 pos = bp.bufpos;
2200 if (bp.contin && bp.hpos != lmargin)
2202 val.hpos = bp.prevhpos - width + lmargin;
2203 did_motion = 1;
2204 pos--;
2207 bp.vpos = vpos;
2209 /* Find first visible newline after which no more is changed. */
2210 tem = find_next_newline (Z - max (end_unchanged, Z - ZV), 1);
2211 if (selective > 0)
2212 while (tem < ZV - 1 && (indented_beyond_p (tem, selective)))
2213 tem = find_next_newline (tem, 1);
2215 /* Compute the cursor position after that newline. */
2216 ep = *compute_motion (pos, vpos, val.hpos, did_motion, tem,
2217 height, - (1 << (BITS_PER_SHORT - 1)),
2218 width, hscroll, pos_tab_offset (w, bp.bufpos), w);
2220 /* If changes reach past the text available on the frame,
2221 just display rest of frame. */
2222 if (ep.bufpos > Z - XFASTINT (w->window_end_pos))
2223 stop_vpos = height;
2224 else
2225 stop_vpos = ep.vpos;
2227 /* If no newline before ep, the line ep is on includes some changes
2228 that must be displayed. Make sure we don't stop before it. */
2229 /* Also, if changes reach all the way until ep.bufpos,
2230 it is possible that something was deleted after the
2231 newline before it, so the following line must be redrawn. */
2232 if (stop_vpos == ep.vpos
2233 && (ep.bufpos == BEGV
2234 || FETCH_CHAR (ep.bufpos - 1) != '\n'
2235 || ep.bufpos == Z - end_unchanged))
2236 stop_vpos = ep.vpos + 1;
2238 cursor_vpos = -1;
2239 overlay_arrow_seen = 0;
2240 zv_strings_seen = 0;
2242 /* If changes do not reach to bottom of window,
2243 figure out how much to scroll the rest of the window */
2244 if (stop_vpos < height)
2246 /* Now determine how far up or down the rest of the window has moved */
2247 epto = pos_tab_offset (w, ep.bufpos);
2248 xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
2249 Z - XFASTINT (w->window_end_pos),
2250 10000, 0, width, hscroll, epto, w);
2251 scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
2253 /* Is everything on frame below the changes whitespace?
2254 If so, no scrolling is really necessary. */
2255 for (i = ep.bufpos; i < xp.bufpos; i++)
2257 tem = FETCH_CHAR (i);
2258 if (tem != ' ' && tem != '\n' && tem != '\t')
2259 break;
2261 if (i == xp.bufpos)
2262 return -2;
2264 XSETFASTINT (w->window_end_vpos,
2265 XFASTINT (w->window_end_vpos) + scroll_amount);
2267 /* Before doing any scrolling, verify that point will be on frame. */
2268 if (PT > ep.bufpos && !(PT <= xp.bufpos && xp.bufpos < height))
2270 if (PT <= xp.bufpos)
2272 pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
2273 PT, height, - (1 << (BITS_PER_SHORT - 1)),
2274 width, hscroll, epto, w);
2276 else
2278 pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos, 1,
2279 PT, height, - (1 << (BITS_PER_SHORT - 1)),
2280 width, hscroll,
2281 pos_tab_offset (w, xp.bufpos), w);
2283 if (pp.bufpos < PT || pp.vpos == height)
2284 return 0;
2285 cursor_vpos = pp.vpos + top;
2286 cursor_hpos = WINDOW_LEFT_MARGIN (w) + minmax (0, pp.hpos, width);
2289 if (stop_vpos - scroll_amount >= height
2290 || ep.bufpos == xp.bufpos)
2292 if (scroll_amount < 0)
2293 stop_vpos -= scroll_amount;
2294 scroll_amount = 0;
2295 /* In this path, we have altered window_end_vpos
2296 and not left it negative.
2297 We must make sure that, in case display is preempted
2298 before the frame changes to reflect what we do here,
2299 further updates will not come to try_window_id
2300 and assume the frame and window_end_vpos match. */
2301 blank_end_of_window = 1;
2303 else if (!scroll_amount)
2305 /* Even if we don't need to scroll, we must adjust the
2306 charstarts of subsequent lines (that we won't redisplay)
2307 according to the amount of text inserted or deleted. */
2308 int oldpos = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0];
2309 int adjust = ep.bufpos - oldpos;
2310 adjust_window_charstarts (w, ep.vpos + top - 1, adjust);
2312 else if (bp.bufpos == Z - end_unchanged)
2314 /* If reprinting everything is nearly as fast as scrolling,
2315 don't bother scrolling. Can happen if lines are short. */
2316 if (scroll_cost (f, bp.vpos + top - scroll_amount,
2317 top + height - max (0, scroll_amount),
2318 scroll_amount)
2319 > xp.bufpos - bp.bufpos - 20)
2320 /* Return "try normal display with same window-start."
2321 Too bad we can't prevent further scroll-thinking. */
2322 return -2;
2323 /* If pure deletion, scroll up as many lines as possible.
2324 In common case of killing a line, this can save the
2325 following line from being overwritten by scrolling
2326 and therefore having to be redrawn. */
2327 tem = scroll_frame_lines (f, bp.vpos + top - scroll_amount,
2328 top + height - max (0, scroll_amount),
2329 scroll_amount, bp.bufpos);
2330 if (!tem)
2331 stop_vpos = height;
2332 else
2334 /* scroll_frame_lines did not properly adjust subsequent
2335 lines' charstarts in the case where the text of the
2336 screen line at bp.vpos has changed.
2337 (This can happen in a deletion that ends in mid-line.)
2338 To adjust properly, we need to make things consistent
2339 at the position ep.
2340 So do a second adjust to make that happen.
2341 Note that stop_vpos >= ep.vpos, so it is sufficient
2342 to update the charstarts for lines at ep.vpos and below. */
2343 int oldstart
2344 = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0];
2345 adjust_window_charstarts (w, ep.vpos + top - 1,
2346 ep.bufpos - oldstart);
2349 else if (scroll_amount)
2351 /* If reprinting everything is nearly as fast as scrolling,
2352 don't bother scrolling. Can happen if lines are short. */
2353 /* Note that if scroll_amount > 0, xp.bufpos - bp.bufpos is an
2354 overestimate of cost of reprinting, since xp.bufpos
2355 would end up below the bottom of the window. */
2356 if (scroll_cost (f, ep.vpos + top - scroll_amount,
2357 top + height - max (0, scroll_amount),
2358 scroll_amount)
2359 > xp.bufpos - ep.bufpos - 20)
2360 /* Return "try normal display with same window-start."
2361 Too bad we can't prevent further scroll-thinking. */
2362 return -2;
2363 tem = scroll_frame_lines (f, ep.vpos + top - scroll_amount,
2364 top + height - max (0, scroll_amount),
2365 scroll_amount, ep.bufpos);
2366 if (!tem) stop_vpos = height;
2370 /* In any case, do not display past bottom of window */
2371 if (stop_vpos >= height)
2373 stop_vpos = height;
2374 scroll_amount = 0;
2377 /* Handle case where pos is before w->start --
2378 can happen if part of line had been clipped and is not clipped now */
2379 if (vpos == 0 && pos < marker_position (w->start))
2380 Fset_marker (w->start, make_number (pos), Qnil);
2382 /* Redisplay the lines where the text was changed */
2383 last_text_vpos = vpos;
2384 tab_offset = pos_tab_offset (w, pos);
2385 /* If we are starting display in mid-character, correct tab_offset
2386 to account for passing the line that that character really starts in. */
2387 if (val.hpos < lmargin)
2388 tab_offset += width;
2389 old_tick = MODIFF;
2390 while (vpos < stop_vpos)
2392 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset,
2393 val.ovstring_chars_done);
2394 /* If display_text_line ran a hook and changed some text,
2395 redisplay all the way to bottom of buffer
2396 So that we show the changes. */
2397 if (old_tick != MODIFF)
2398 stop_vpos = height;
2399 tab_offset += width;
2400 if (val.vpos) tab_offset = 0;
2401 if (pos != val.bufpos)
2402 last_text_vpos
2403 /* Next line, unless prev line ended in end of buffer with no cr */
2404 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
2405 pos = val.bufpos;
2408 /* There are two cases:
2409 1) we have displayed down to the bottom of the window
2410 2) we have scrolled lines below stop_vpos by scroll_amount */
2412 if (vpos == height)
2414 /* If last line is continued in middle of character,
2415 include the split character in the text considered on the frame */
2416 if (val.hpos < lmargin)
2417 val.bufpos++;
2418 XSETFASTINT (w->window_end_vpos, last_text_vpos);
2419 XSETFASTINT (w->window_end_pos, Z - val.bufpos);
2422 /* If scrolling made blank lines at window bottom,
2423 redisplay to fill those lines */
2424 if (scroll_amount < 0)
2426 /* Don't consider these lines for general-purpose scrolling.
2427 That will save time in the scrolling computation. */
2428 FRAME_SCROLL_BOTTOM_VPOS (f) = xp.vpos;
2429 vpos = xp.vpos;
2430 pos = xp.bufpos;
2431 val.hpos = lmargin;
2432 if (pos == ZV)
2433 vpos = height + scroll_amount;
2434 else if (xp.contin && xp.hpos != lmargin)
2436 val.hpos = xp.prevhpos - width + lmargin;
2437 pos--;
2440 blank_end_of_window = 1;
2441 tab_offset = pos_tab_offset (w, pos);
2442 /* If we are starting display in mid-character, correct tab_offset
2443 to account for passing the line that that character starts in. */
2444 if (val.hpos < lmargin)
2445 tab_offset += width;
2447 while (vpos < height)
2449 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset,
2450 val.ovstring_chars_done);
2451 tab_offset += width;
2452 if (val.vpos) tab_offset = 0;
2453 pos = val.bufpos;
2456 /* Here is a case where display_text_line sets cursor_vpos wrong.
2457 Make it be fixed up, below. */
2458 if (xp.bufpos == ZV
2459 && xp.bufpos == PT)
2460 cursor_vpos = -1;
2463 /* If bottom just moved off end of frame, change mode line percentage. */
2464 if (XFASTINT (w->window_end_pos) == 0
2465 && Z != val.bufpos)
2466 w->update_mode_line = Qt;
2468 /* Attempt to adjust end-of-text positions to new bottom line */
2469 if (scroll_amount)
2471 delta = height - xp.vpos;
2472 if (delta < 0
2473 || (delta > 0 && xp.bufpos <= ZV)
2474 || (delta == 0 && xp.hpos))
2476 val = *vmotion (Z - XFASTINT (w->window_end_pos), delta, w);
2477 XSETFASTINT (w->window_end_pos, Z - val.bufpos);
2478 XSETFASTINT (w->window_end_vpos,
2479 XFASTINT (w->window_end_vpos) + val.vpos);
2483 w->window_end_valid = Qnil;
2485 /* If point was not in a line that was displayed, find it */
2486 if (cursor_vpos < 0)
2488 findpoint:
2489 val = *compute_motion (start, 0, lmargin, 0, PT, 10000, 10000,
2490 width, hscroll, pos_tab_offset (w, start), w);
2491 /* Admit failure if point is off frame now */
2492 if (val.vpos >= height)
2494 for (vpos = 0; vpos < height; vpos++)
2495 cancel_line (vpos + top, f);
2496 return 0;
2498 cursor_vpos = val.vpos + top;
2499 cursor_hpos = WINDOW_LEFT_MARGIN (w) + minmax (0, val.hpos, width);
2502 FRAME_CURSOR_X (f) = cursor_hpos;
2503 FRAME_CURSOR_Y (f) = cursor_vpos;
2505 if (debug_end_pos)
2507 val = *compute_motion (start, 0, lmargin, 0, ZV,
2508 height, - (1 << (BITS_PER_SHORT - 1)),
2509 width, hscroll, pos_tab_offset (w, start), w);
2510 if (val.vpos != XFASTINT (w->window_end_vpos))
2511 abort ();
2512 if (XFASTINT (w->window_end_pos)
2513 != Z - val.bufpos)
2514 abort ();
2517 return 1;
2520 /* Copy LEN glyphs starting address FROM to the rope TO.
2521 But don't actually copy the parts that would come in before S.
2522 Value is TO, advanced past the copied data.
2523 F is the frame we are displaying in. */
2525 static GLYPH *
2526 copy_part_of_rope (f, to, s, from, len, face)
2527 FRAME_PTR f;
2528 register GLYPH *to; /* Copy to here. */
2529 register GLYPH *s; /* Starting point. */
2530 Lisp_Object *from; /* Data to copy. */
2531 int len;
2532 int face; /* Face to apply to glyphs which don't specify one. */
2534 int n = len;
2535 register Lisp_Object *fp = from;
2536 /* These cache the results of the last call to compute_glyph_face. */
2537 int last_code = -1;
2538 int last_merged = 0;
2540 #ifdef HAVE_FACES
2541 if (! FRAME_TERMCAP_P (f))
2542 while (n--)
2544 int glyph = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
2545 int facecode;
2547 if (FAST_GLYPH_FACE (glyph) == 0)
2548 /* If GLYPH has no face code, use FACE. */
2549 facecode = face;
2550 else if (FAST_GLYPH_FACE (glyph) == last_code)
2551 /* If it's same as previous glyph, use same result. */
2552 facecode = last_merged;
2553 else
2555 /* Merge this glyph's face and remember the result. */
2556 last_code = FAST_GLYPH_FACE (glyph);
2557 last_merged = facecode = compute_glyph_face (f, last_code, face);
2560 if (to >= s)
2561 *to = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), facecode);
2562 ++to;
2563 ++fp;
2565 else
2566 #endif
2567 while (n--)
2569 if (to >= s) *to = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
2570 ++to;
2571 ++fp;
2573 return to;
2576 /* Correct a glyph by replacing its specified user-level face code
2577 with a displayable computed face code. */
2579 static GLYPH
2580 fix_glyph (f, glyph, cface)
2581 FRAME_PTR f;
2582 GLYPH glyph;
2583 int cface;
2585 #ifdef HAVE_FACES
2586 if (! FRAME_TERMCAP_P (f))
2588 if (FAST_GLYPH_FACE (glyph) != 0)
2589 cface = compute_glyph_face (f, FAST_GLYPH_FACE (glyph), cface);
2590 glyph = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), cface);
2592 #endif
2593 return glyph;
2596 /* Display one line of window W, starting at position START in W's buffer.
2598 Display starting at horizontal position HPOS, expressed relative to
2599 W's left edge. In situations where the text at START shouldn't
2600 start at the left margin (i.e. when the window is hscrolled, or
2601 we're continuing a line which left off in the midst of a
2602 multi-column character), HPOS should be negative; we throw away
2603 characters up 'til hpos = 0. So, HPOS must take hscrolling into
2604 account.
2606 TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
2608 OVSTR_DONE is the number of chars of overlay before/after strings
2609 at this position which have already been processed.
2611 Display on position VPOS on the frame. It is origin 0, relative to
2612 the top of the frame, not W.
2614 Returns a STRUCT POSITION giving character to start next line with
2615 and where to display it, including a zero or negative hpos.
2616 The vpos field is not really a vpos; it is 1 unless the line is continued */
2618 struct position val_display_text_line;
2620 static struct position *
2621 display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
2622 struct window *w;
2623 int start;
2624 int vpos;
2625 int hpos;
2626 int taboffset;
2627 int ovstr_done;
2629 register int pos = start;
2630 register int c;
2631 register GLYPH *p1;
2632 register int pause;
2633 register unsigned char *p;
2634 GLYPH *endp;
2635 register GLYPH *leftmargin;
2636 register GLYPH *p1prev;
2637 register GLYPH *p1start;
2638 int prevpos;
2639 int *charstart;
2640 FRAME_PTR f = XFRAME (w->frame);
2641 int tab_width = XINT (current_buffer->tab_width);
2642 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
2643 int width = window_internal_width (w) - 1;
2644 struct position val;
2645 int lastpos;
2646 int invis;
2647 int last_invis_skip = 0;
2648 Lisp_Object last_invis_prop;
2649 int hscroll = XINT (w->hscroll);
2650 int truncate = (hscroll
2651 || (truncate_partial_width_windows
2652 && !WINDOW_FULL_WIDTH_P (w))
2653 || !NILP (current_buffer->truncate_lines));
2655 /* 1 if we should highlight the region. */
2656 int highlight_region
2657 = (!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active)
2658 && XWINDOW (current_buffer->last_selected_window) == w);
2659 int region_beg, region_end;
2661 int selective = (INTEGERP (current_buffer->selective_display)
2662 ? XINT (current_buffer->selective_display)
2663 : !NILP (current_buffer->selective_display) ? -1 : 0);
2664 register struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
2665 register struct Lisp_Char_Table *dp = window_display_table (w);
2667 Lisp_Object default_invis_vector[3];
2668 /* Number of characters of ellipsis to display after an invisible line
2669 if it calls for an ellipsis.
2670 Note that this value can be nonzero regardless of whether
2671 selective display is enabled--you must check that separately. */
2672 int selective_rlen
2673 = (dp && VECTORP (DISP_INVIS_VECTOR (dp))
2674 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size
2675 : !NILP (current_buffer->selective_display_ellipses) ? 3 : 0);
2676 /* This is the sequence of Lisp objects to display
2677 when there are invisible lines. */
2678 Lisp_Object *invis_vector_contents
2679 = (dp && VECTORP (DISP_INVIS_VECTOR (dp))
2680 ? XVECTOR (DISP_INVIS_VECTOR (dp))->contents
2681 : default_invis_vector);
2683 GLYPH truncator = (dp == 0 || !INTEGERP (DISP_TRUNC_GLYPH (dp))
2684 ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
2685 GLYPH continuer = (dp == 0 || !INTEGERP (DISP_CONTINUE_GLYPH (dp))
2686 ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
2688 /* The next buffer location at which the face should change, due
2689 to overlays or text property changes. */
2690 int next_face_change;
2692 /* The next location where the `invisible' property changes, or an
2693 overlay starts or ends. */
2694 int next_boundary;
2696 /* The face we're currently using. */
2697 int current_face = 0;
2698 int i;
2700 XSETFASTINT (default_invis_vector[2], '.');
2701 default_invis_vector[0] = default_invis_vector[1] = default_invis_vector[2];
2703 hpos += WINDOW_LEFT_MARGIN (w);
2704 get_display_line (f, vpos, WINDOW_LEFT_MARGIN (w));
2705 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
2707 /* Show where to highlight the region. */
2708 if (highlight_region && XMARKER (current_buffer->mark)->buffer != 0
2709 /* Maybe highlight only in selected window. */
2710 && (highlight_nonselected_windows
2711 || w == XWINDOW (selected_window)))
2713 region_beg = marker_position (current_buffer->mark);
2714 if (PT < region_beg)
2716 region_end = region_beg;
2717 region_beg = PT;
2719 else
2720 region_end = PT;
2721 w->region_showing = Qt;
2723 else
2724 region_beg = region_end = -1;
2726 if (MINI_WINDOW_P (w)
2727 && start == BEG
2728 && vpos == XFASTINT (w->top))
2730 if (! NILP (minibuf_prompt))
2732 minibuf_prompt_width
2733 = (display_string (w, vpos, XSTRING (minibuf_prompt)->data,
2734 XSTRING (minibuf_prompt)->size, hpos,
2735 /* Display a space if we truncate. */
2736 ' ',
2737 1, -1,
2738 /* Truncate the prompt a little before the
2739 margin, so user input can at least start
2740 on the first line. */
2741 w->width > 10 ? w->width - 4 : -1)
2742 - hpos);
2743 hpos += minibuf_prompt_width;
2744 taboffset -= minibuf_prompt_width;
2746 else
2747 minibuf_prompt_width = 0;
2750 /* If we're hscrolled at all, use compute_motion to skip over any
2751 text off the left edge of the window. compute_motion may know
2752 tricks to do this faster than we can. */
2753 if (hpos < 0)
2755 struct position *left_edge
2756 = compute_motion (pos, vpos, hpos, 0,
2757 ZV, vpos, 0,
2758 width, hscroll, taboffset, w);
2760 /* Retrieve the buffer position and column provided by
2761 compute_motion. We can't assume that the column will be
2762 zero, because you may have multi-column characters crossing
2763 the left margin.
2765 compute_motion may have moved us past the screen position we
2766 requested, if we hit a multi-column character, or the end of
2767 the line. If so, back up. */
2768 if (left_edge->vpos > vpos
2769 || left_edge->hpos > 0)
2771 pos = left_edge->bufpos - 1;
2772 hpos = left_edge->prevhpos;
2774 else
2776 pos = left_edge->bufpos;
2777 hpos = left_edge->hpos;
2781 desired_glyphs->bufp[vpos] = start;
2782 p1 = desired_glyphs->glyphs[vpos] + hpos;
2783 p1start = p1;
2784 charstart = desired_glyphs->charstarts[vpos] + hpos;
2785 /* In case we don't ever write anything into it... */
2786 desired_glyphs->charstarts[vpos][WINDOW_LEFT_MARGIN (w)] = -1;
2787 leftmargin = desired_glyphs->glyphs[vpos] + WINDOW_LEFT_MARGIN (w);
2788 endp = leftmargin + width;
2790 /* Arrange the overlays nicely for our purposes. Usually, we call
2791 display_text_line on only one line at a time, in which case this
2792 can't really hurt too much, or we call it on lines which appear
2793 one after another in the buffer, in which case all calls to
2794 recenter_overlay_lists but the first will be pretty cheap. */
2795 recenter_overlay_lists (current_buffer, pos);
2797 /* Loop generating characters.
2798 Stop at end of buffer, before newline,
2799 if reach or pass continuation column,
2800 or at face change. */
2801 pause = pos;
2802 next_face_change = pos;
2803 next_boundary = pos;
2804 p1prev = p1;
2805 prevpos = pos;
2806 while (1)
2808 if (pos >= pause)
2810 int e_t_h;
2812 while (pos == next_boundary)
2814 Lisp_Object position, limit, prop, ww;
2816 /* Display the overlay strings here, unless we're at ZV
2817 and have already displayed the appropriate strings
2818 on an earlier line. */
2819 if (pos < ZV || !zv_strings_seen++)
2821 int ovlen;
2822 unsigned char *ovstr;
2823 ovlen = overlay_strings (pos, w, &ovstr);
2825 if (ovlen > 0)
2827 /* Skip the ones we did in a previous line. */
2828 ovstr += ovstr_done;
2829 ovlen -= ovstr_done;
2831 /* Start outputting. */
2832 for (; ovlen; ovlen--, ovstr++)
2834 if (p1 >= leftmargin && p1 < endp)
2835 *p1 = MAKE_GLYPH (f, *ovstr, current_face);
2836 p1++;
2837 ovstr_done++;
2839 /* If we did all the overlay strings
2840 and we have room for text, clear ovstr_done
2841 just for neatness' sake. */
2842 if (ovlen == 0 && p1 < endp)
2843 ovstr_done = 0;
2847 /* Did we reach point? Record the cursor location. */
2848 if (pos == PT && cursor_vpos < 0)
2850 cursor_vpos = vpos;
2851 cursor_hpos = p1 - leftmargin;
2854 if (pos >= ZV)
2855 break;
2857 XSETFASTINT (position, pos);
2858 limit = Fnext_overlay_change (position);
2859 #ifdef USE_TEXT_PROPERTIES
2860 /* This is just an estimate to give reasonable
2861 performance; nothing should go wrong if it is too small. */
2862 if (XFASTINT (limit) > pos + 50)
2863 XSETFASTINT (limit, pos + 50);
2864 limit = Fnext_single_property_change (position, Qinvisible,
2865 Fcurrent_buffer (), limit);
2866 #endif
2867 next_boundary = XFASTINT (limit);
2868 /* if the `invisible' property is set, we can skip to
2869 the next property change. */
2870 XSETWINDOW (ww, w);
2871 prop = Fget_char_property (position, Qinvisible, ww);
2872 if (TEXT_PROP_MEANS_INVISIBLE (prop))
2874 if (pos < PT && next_boundary >= PT)
2876 cursor_vpos = vpos;
2877 cursor_hpos = p1 - leftmargin;
2879 pos = next_boundary;
2880 last_invis_skip = pos;
2881 last_invis_prop = prop;
2885 /* Did we reach point? Record the cursor location. */
2886 if (pos == PT && cursor_vpos < 0)
2888 cursor_vpos = vpos;
2889 cursor_hpos = p1 - leftmargin;
2892 /* Did we hit the end of the visible region of the buffer?
2893 Stop here. */
2894 if (pos >= ZV)
2896 /* Update charstarts for the end of this line. */
2897 /* Do nothing if off the left edge or at the right edge. */
2898 if (p1 >= leftmargin && p1 + 1 != endp)
2900 int *p2x = &charstart[(p1 < leftmargin
2901 ? leftmargin : p1)
2902 - p1start];
2903 *p2x++ = pos;
2905 break;
2908 /* Figure out where (if at all) the
2909 redisplay_end_trigger-hook should run. */
2910 if (MARKERP (w->redisplay_end_trigger)
2911 && XMARKER (w->redisplay_end_trigger)->buffer != 0)
2912 e_t_h = marker_position (w->redisplay_end_trigger);
2913 else if (INTEGERP (w->redisplay_end_trigger))
2914 e_t_h = XINT (w->redisplay_end_trigger);
2915 else
2916 e_t_h = ZV;
2918 /* If we've gone past the place to run a hook,
2919 run the hook. */
2920 if (pos >= e_t_h && e_t_h != ZV)
2922 Lisp_Object args[3];
2924 args[0] = Qredisplay_end_trigger_functions;
2925 XSETWINDOW (args[1], w);
2926 XSETINT (args[2], e_t_h);
2928 /* Since we are *trying* to run these functions,
2929 don't try to run them again, even if they get an error. */
2930 w->redisplay_end_trigger = Qnil;
2931 Frun_hook_with_args (3, args);
2933 e_t_h = ZV;
2934 /* Notice if it changed the face of this character. */
2935 next_face_change = pos;
2938 #ifdef HAVE_FACES
2939 /* Did we hit a face change? Figure out what face we should
2940 use now. We also hit this the first time through the
2941 loop, to see what face we should start with. */
2942 if (pos >= next_face_change
2943 && (FRAME_WINDOW_P (f) || FRAME_MSDOS_P (f)))
2944 current_face = compute_char_face (f, w, pos,
2945 region_beg, region_end,
2946 &next_face_change, pos + 50, 0);
2947 #endif
2949 /* Compute the next place we need to stop
2950 and do something special; set PAUSE. */
2952 pause = ZV;
2954 if (pos < next_boundary && next_boundary < pause)
2955 pause = next_boundary;
2956 if (pos < next_face_change && next_face_change < pause)
2957 pause = next_face_change;
2959 if (e_t_h < pause)
2960 pause = e_t_h;
2962 /* Wouldn't you hate to read the next line to someone over
2963 the phone? */
2964 if (pos < PT && PT < pause)
2965 pause = PT;
2966 if (pos < GPT && GPT < pause)
2967 pause = GPT;
2969 p = &FETCH_CHAR (pos);
2972 if (p1 >= endp)
2973 break;
2975 p1prev = p1;
2977 c = *p++;
2978 /* Let a display table override all standard display methods. */
2979 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
2981 p1 = copy_part_of_rope (f, p1, leftmargin,
2982 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
2983 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
2984 current_face);
2986 else if (c >= 040 && c < 0177)
2988 if (p1 >= leftmargin)
2989 *p1 = MAKE_GLYPH (f, c, current_face);
2990 p1++;
2992 else if (c == '\n')
2994 invis = 0;
2995 if (last_invis_skip == pos
2996 && TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (last_invis_prop))
2997 invis = 1;
2998 while (pos + 1 < ZV
2999 && selective > 0
3000 && indented_beyond_p (pos + 1, selective))
3002 invis = 1;
3003 pos = find_next_newline (pos + 1, 1);
3004 if (FETCH_CHAR (pos - 1) == '\n')
3005 pos--;
3007 if (invis && selective_rlen > 0 && p1 >= leftmargin)
3009 p1 += selective_rlen;
3010 if (p1 - leftmargin > width)
3011 p1 = endp;
3012 copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
3013 (p1 - p1prev), current_face);
3015 #ifdef HAVE_FACES
3016 /* Draw the face of the newline character as extending all the
3017 way to the end of the frame line. */
3018 if (current_face)
3020 if (p1 < leftmargin)
3021 p1 = leftmargin;
3022 while (p1 < endp)
3023 *p1++ = FAST_MAKE_GLYPH (' ', current_face);
3025 #endif
3027 /* Update charstarts for the newline that ended this line. */
3028 /* Do nothing here for a char that's entirely off the left edge
3029 or if it starts at the right edge. */
3030 if (p1 >= leftmargin && p1prev != endp)
3032 /* Store the newline's position into charstarts
3033 for the column where the newline starts.
3034 Store -1 for the rest of the glyphs it occupies. */
3035 int *p2x = &charstart[(p1prev < leftmargin
3036 ? leftmargin : p1prev)
3037 - p1start];
3038 int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
3040 *p2x++ = pos;
3041 while (p2x < p2)
3042 *p2x++ = -1;
3045 break;
3047 else if (c == '\t')
3051 if (p1 >= leftmargin && p1 < endp)
3052 *p1 = MAKE_GLYPH (f, ' ', current_face);
3053 p1++;
3055 while ((p1 - leftmargin + taboffset + hscroll - (hscroll > 0))
3056 % tab_width);
3058 else if (c == Ctl ('M') && selective == -1)
3060 pos = find_next_newline (pos, 1);
3061 if (FETCH_CHAR (pos - 1) == '\n')
3062 pos--;
3063 if (selective_rlen > 0)
3065 p1 += selective_rlen;
3066 if (p1 - leftmargin > width)
3067 p1 = endp;
3068 copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
3069 (p1 - p1prev), current_face);
3071 #ifdef HAVE_FACES
3072 /* Draw the face of the newline character as extending all the
3073 way to the end of the frame line. */
3074 if (current_face)
3076 if (p1 < leftmargin)
3077 p1 = leftmargin;
3078 while (p1 < endp)
3079 *p1++ = FAST_MAKE_GLYPH (' ', current_face);
3081 #endif
3083 /* Update charstarts for the ^M that ended this line. */
3084 /* Do nothing here for a char that's entirely off the left edge
3085 or if it starts at the right edge. */
3086 if (p1 >= leftmargin && p1prev != endp)
3088 /* Store the newline's position into charstarts
3089 for the column where the newline starts.
3090 Store -1 for the rest of the glyphs it occupies. */
3091 int *p2x = &charstart[(p1prev < leftmargin
3092 ? leftmargin : p1prev)
3093 - p1start];
3094 int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
3096 *p2x++ = pos;
3097 while (p2x < p2)
3098 *p2x++ = -1;
3100 break;
3102 else if (c < 0200 && ctl_arrow)
3104 if (p1 >= leftmargin)
3105 *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
3106 ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
3107 current_face);
3108 p1++;
3109 if (p1 >= leftmargin && p1 < endp)
3110 *p1 = MAKE_GLYPH (f, c ^ 0100, current_face);
3111 p1++;
3113 else
3115 if (p1 >= leftmargin)
3116 *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
3117 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
3118 current_face);
3119 p1++;
3120 if (p1 >= leftmargin && p1 < endp)
3121 *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face);
3122 p1++;
3123 if (p1 >= leftmargin && p1 < endp)
3124 *p1 = MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face);
3125 p1++;
3126 if (p1 >= leftmargin && p1 < endp)
3127 *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face);
3128 p1++;
3131 prevpos = pos;
3132 pos++;
3134 /* Update charstarts for the character just output. */
3136 /* Do nothing here for a char that's entirely off the left edge. */
3137 if (p1 >= leftmargin)
3139 /* Store the char's position into charstarts
3140 for the first glyph occupied by this char.
3141 Store -1 for the rest of the glyphs it occupies. */
3142 if (p1 != p1prev)
3144 int *p2x = &charstart[(p1prev < leftmargin
3145 ? leftmargin : p1prev)
3146 - p1start];
3147 int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
3149 if (p2x < p2)
3150 *p2x++ = prevpos;
3151 while (p2x < p2)
3152 *p2x++ = -1;
3157 val.hpos = - XINT (w->hscroll);
3158 if (val.hpos)
3159 val.hpos++;
3161 val.vpos = 1;
3163 lastpos = pos;
3165 /* Store 0 in this charstart line for the positions where
3166 there is no character. But do leave what was recorded
3167 for the character that ended the line. */
3168 /* Add 1 in the endtest to compensate for the fact that ENDP was
3169 made from WIDTH, which is 1 less than the window's actual
3170 internal width. */
3171 i = p1 - p1start + 1;
3172 if (p1 < leftmargin)
3173 i += leftmargin - p1;
3174 for (; i < endp - p1start + 1; i++)
3175 charstart[i] = 0;
3177 /* Handle continuation in middle of a character */
3178 /* by backing up over it */
3179 if (p1 > endp)
3181 /* Don't back up if we never actually displayed any text.
3182 This occurs when the minibuffer prompt takes up the whole line. */
3183 if (p1prev)
3185 /* Start the next line with that same character */
3186 pos--;
3187 /* but at negative hpos, to skip the columns output on this line. */
3188 val.hpos += p1prev - endp;
3191 /* Keep in this line everything up to the continuation column. */
3192 p1 = endp;
3195 /* Finish deciding which character to start the next line on,
3196 and what hpos to start it at.
3197 Also set `lastpos' to the last position which counts as "on this line"
3198 for cursor-positioning. */
3200 if (pos < ZV)
3202 if (FETCH_CHAR (pos) == '\n')
3204 /* If stopped due to a newline, start next line after it */
3205 pos++;
3206 /* Check again for hidden lines, in case the newline occurred exactly
3207 at the right margin. */
3208 while (pos < ZV && selective > 0
3209 && indented_beyond_p (pos, selective))
3210 pos = find_next_newline (pos, 1);
3212 else
3213 /* Stopped due to right margin of window */
3215 if (truncate)
3217 *p1++ = fix_glyph (f, truncator, 0);
3218 /* Truncating => start next line after next newline,
3219 and point is on this line if it is before the newline,
3220 and skip none of first char of next line */
3222 pos = find_next_newline (pos, 1);
3223 while (pos < ZV && selective > 0
3224 && indented_beyond_p (pos, selective));
3225 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
3227 lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
3229 else
3231 *p1++ = fix_glyph (f, continuer, 0);
3232 val.vpos = 0;
3233 lastpos--;
3238 /* If point is at eol or in invisible text at eol,
3239 record its frame location now. */
3241 if (start <= PT && PT <= lastpos && cursor_vpos < 0)
3243 cursor_vpos = vpos;
3244 cursor_hpos = p1 - leftmargin;
3247 if (cursor_vpos == vpos)
3249 if (cursor_hpos < 0) cursor_hpos = 0;
3250 if (cursor_hpos > width) cursor_hpos = width;
3251 cursor_hpos += WINDOW_LEFT_MARGIN (w);
3252 if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
3254 if (!(cursor_in_echo_area && FRAME_HAS_MINIBUF_P (f)
3255 && EQ (FRAME_MINIBUF_WINDOW (f), minibuf_window)))
3257 FRAME_CURSOR_Y (f) = cursor_vpos;
3258 FRAME_CURSOR_X (f) = cursor_hpos;
3261 if (w == XWINDOW (selected_window))
3263 /* Line is not continued and did not start
3264 in middle of character */
3265 if ((hpos - WINDOW_LEFT_MARGIN (w)
3266 == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
3267 && val.vpos)
3269 this_line_bufpos = start;
3270 this_line_buffer = current_buffer;
3271 this_line_vpos = cursor_vpos;
3272 this_line_start_hpos = hpos;
3273 this_line_endpos = Z - lastpos;
3275 else
3276 this_line_bufpos = 0;
3281 /* If hscroll and line not empty, insert truncation-at-left marker */
3282 if (hscroll && lastpos != start)
3284 *leftmargin = fix_glyph (f, truncator, 0);
3285 if (p1 <= leftmargin)
3286 p1 = leftmargin + 1;
3289 if (!WINDOW_RIGHTMOST_P (w))
3291 endp++;
3292 if (p1 < leftmargin) p1 = leftmargin;
3293 while (p1 < endp) *p1++ = SPACEGLYPH;
3295 /* Don't draw vertical bars if we're using scroll bars. They're
3296 covered up by the scroll bars, and it's distracting to see
3297 them when the scroll bar windows are flickering around to be
3298 reconfigured. */
3299 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3301 int i;
3302 for (i = 0; i < FRAME_SCROLL_BAR_COLS (f); i++)
3303 *p1++ = SPACEGLYPH;
3305 else if (!FRAME_HAS_VERTICAL_SCROLL_BARS (f))
3306 *p1++ = (dp && INTEGERP (DISP_BORDER_GLYPH (dp))
3307 ? DISP_BORDER_GLYPH (dp)
3308 : '|');
3310 desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
3311 p1 - desired_glyphs->glyphs[vpos]);
3312 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
3314 /* If the start of this line is the overlay arrow-position,
3315 then put the arrow string into the display-line. */
3317 if (MARKERP (Voverlay_arrow_position)
3318 && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
3319 && start == marker_position (Voverlay_arrow_position)
3320 && STRINGP (Voverlay_arrow_string)
3321 && ! overlay_arrow_seen)
3323 unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
3324 int i;
3325 int len = XSTRING (Voverlay_arrow_string)->size;
3326 int arrow_end;
3328 if (len > width)
3329 len = width;
3330 #ifdef HAVE_FACES
3331 if (!NULL_INTERVAL_P (XSTRING (Voverlay_arrow_string)->intervals))
3333 /* If the arrow string has text props, obey them when displaying. */
3334 for (i = 0; i < len; i++)
3336 int c = p[i];
3337 Lisp_Object face, ilisp;
3338 int newface;
3340 XSETFASTINT (ilisp, i);
3341 face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string);
3342 newface = compute_glyph_face_1 (f, face, 0);
3343 leftmargin[i] = FAST_MAKE_GLYPH (c, newface);
3346 else
3347 #endif /* HAVE_FACES */
3349 for (i = 0; i < len; i++)
3350 leftmargin[i] = p[i];
3353 /* Bug in SunOS 4.1.1 compiler requires this intermediate variable. */
3354 arrow_end = (leftmargin - desired_glyphs->glyphs[vpos]) + len;
3355 if (desired_glyphs->used[vpos] < arrow_end)
3356 desired_glyphs->used[vpos] = arrow_end;
3358 overlay_arrow_seen = 1;
3361 val.bufpos = pos;
3362 val.ovstring_chars_done = ovstr_done;
3363 val_display_text_line = val;
3364 return &val_display_text_line;
3367 /* Redisplay the menu bar in the frame for window W. */
3369 static void
3370 display_menu_bar (w)
3371 struct window *w;
3373 Lisp_Object items, tail;
3374 register int vpos = 0;
3375 register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
3376 int maxendcol = FRAME_WIDTH (f);
3377 int hpos = 0;
3378 int i;
3380 #ifdef HAVE_NTGUI
3381 if (!NILP (Vwindow_system))
3382 return;
3383 #endif
3385 #ifdef USE_X_TOOLKIT
3386 if (FRAME_X_P (f))
3387 return;
3388 #endif /* USE_X_TOOLKIT */
3390 get_display_line (f, vpos, 0);
3392 items = FRAME_MENU_BAR_ITEMS (f);
3393 for (i = 0; i < XVECTOR (items)->size; i += 4)
3395 Lisp_Object pos, string;
3396 string = XVECTOR (items)->contents[i + 1];
3397 if (NILP (string))
3398 break;
3400 XSETFASTINT (XVECTOR (items)->contents[i + 3], hpos);
3402 if (hpos < maxendcol)
3403 hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
3404 XSTRING (string)->data,
3405 XSTRING (string)->size,
3406 hpos, 0, 0, hpos, maxendcol);
3407 /* Put a space between items. */
3408 if (hpos < maxendcol)
3410 int hpos1 = hpos + 1;
3411 hpos = display_string (w, vpos, "", 0, hpos, 0, 0,
3412 min (hpos1, maxendcol), maxendcol);
3416 FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
3417 FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
3419 /* Fill out the line with spaces. */
3420 if (maxendcol > hpos)
3421 hpos = display_string (w, vpos, "", 0, hpos, 0, 0, maxendcol, maxendcol);
3423 /* Clear the rest of the lines allocated to the menu bar. */
3424 vpos++;
3425 while (vpos < FRAME_MENU_BAR_LINES (f))
3426 get_display_line (f, vpos++, 0);
3429 /* Display the mode line for window w */
3431 static void
3432 display_mode_line (w)
3433 struct window *w;
3435 register int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
3436 register int left = WINDOW_LEFT_MARGIN (w);
3437 register int right = WINDOW_RIGHT_MARGIN (w);
3438 register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
3440 line_number_displayed = 0;
3441 w->column_number_displayed = Qnil;
3443 get_display_line (f, vpos, left);
3445 /* Temporarily make frame F's kboard the current kboard
3446 so that kboard-local variables in the mode_line_format
3447 will get the right values. */
3448 push_frame_kboard (f);
3450 display_mode_element (w, vpos, left, 0, right, right,
3451 current_buffer->mode_line_format);
3453 pop_frame_kboard ();
3455 FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
3457 /* Put the mode line in inverse video.
3458 Use faces if possible, since that lets us handle
3459 partial-width windows and avoid inverting the scroll bar columns. */
3460 #ifdef HAVE_FACES
3461 if (! FRAME_TERMCAP_P (f) && mode_line_inverse_video)
3463 /* For a partial width window, explicitly set face of each glyph. */
3464 int i;
3465 GLYPH *ptr = FRAME_DESIRED_GLYPHS (f)->glyphs[vpos];
3466 for (i = left; i < right; ++i)
3467 ptr[i] = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (ptr[i]), 1);
3469 #endif
3471 /* Make the mode line inverse video if the entire line
3472 is made of mode lines.
3473 I.e. if this window is full width,
3474 or if it is the child of a full width window
3475 (which implies that that window is split side-by-side
3476 and the rest of this line is mode lines of the sibling windows). */
3477 else if (WINDOW_FULL_WIDTH_P (w)
3478 || WINDOW_FULL_WIDTH_P (XWINDOW (w->parent)))
3479 FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
3482 /* Contribute ELT to the mode line for window W.
3483 How it translates into text depends on its data type.
3485 VPOS is the position of the mode line being displayed.
3487 HPOS is the position (absolute on frame) where this element's text
3488 should start. The output is truncated automatically at the right
3489 edge of window W.
3491 DEPTH is the depth in recursion. It is used to prevent
3492 infinite recursion here.
3494 MINENDCOL is the hpos before which the element may not end.
3495 The element is padded at the right with spaces if nec
3496 to reach this column.
3498 MAXENDCOL is the hpos past which this element may not extend.
3499 If MINENDCOL is > MAXENDCOL, MINENDCOL takes priority.
3500 (This is necessary to make nested padding and truncation work.)
3502 Returns the hpos of the end of the text generated by ELT.
3503 The next element will receive that value as its HPOS arg,
3504 so as to concatenate the elements. */
3506 static int
3507 display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
3508 struct window *w;
3509 register int vpos, hpos;
3510 int depth;
3511 int minendcol;
3512 register int maxendcol;
3513 register Lisp_Object elt;
3515 tail_recurse:
3516 if (depth > 10)
3517 goto invalid;
3519 depth++;
3521 switch (SWITCH_ENUM_CAST (XTYPE (elt)))
3523 case Lisp_String:
3525 /* A string: output it and check for %-constructs within it. */
3526 register unsigned char c;
3527 register unsigned char *this = XSTRING (elt)->data;
3529 while (hpos < maxendcol && *this)
3531 unsigned char *last = this;
3532 while ((c = *this++) != '\0' && c != '%')
3534 if (this - 1 != last)
3536 register int lim = --this - last + hpos;
3537 if (frame_title_ptr)
3538 hpos = store_frame_title (last, hpos, min (lim, maxendcol));
3539 else
3540 hpos = display_string (w, vpos, last, -1, hpos, 0, 1,
3541 hpos, min (lim, maxendcol));
3543 else /* c == '%' */
3545 register int minendcol;
3546 register int spec_width = 0;
3548 /* We can't allow -ve args due to the "%-" construct */
3549 /* Argument specifies minwidth but not maxwidth
3550 (maxwidth can be specified by
3551 (<negative-number> . <stuff>) mode-line elements) */
3553 while ((c = *this++) >= '0' && c <= '9')
3555 spec_width = spec_width * 10 + (c - '0');
3558 minendcol = hpos + spec_width;
3559 if (minendcol > maxendcol)
3561 spec_width = maxendcol - hpos;
3562 minendcol = maxendcol;
3565 if (c == 'M')
3566 hpos = display_mode_element (w, vpos, hpos, depth,
3567 spec_width, maxendcol,
3568 Vglobal_mode_string);
3569 else if (c != 0)
3571 char *spec = decode_mode_spec (w, c, spec_width,
3572 maxendcol - hpos);
3573 if (frame_title_ptr)
3574 hpos = store_frame_title (spec, minendcol, maxendcol);
3575 else
3576 hpos = display_string (w, vpos, spec, -1,
3577 hpos, 0, 1,
3578 minendcol, maxendcol);
3583 break;
3585 case Lisp_Symbol:
3586 /* A symbol: process the value of the symbol recursively
3587 as if it appeared here directly. Avoid error if symbol void.
3588 Special case: if value of symbol is a string, output the string
3589 literally. */
3591 register Lisp_Object tem;
3592 tem = Fboundp (elt);
3593 if (!NILP (tem))
3595 tem = Fsymbol_value (elt);
3596 /* If value is a string, output that string literally:
3597 don't check for % within it. */
3598 if (STRINGP (tem))
3600 if (frame_title_ptr)
3601 hpos = store_frame_title (XSTRING (tem)->data,
3602 minendcol, maxendcol);
3603 else
3604 hpos = display_string (w, vpos, XSTRING (tem)->data,
3605 XSTRING (tem)->size,
3606 hpos, 0, 1, minendcol, maxendcol);
3608 /* Give up right away for nil or t. */
3609 else if (!EQ (tem, elt))
3610 { elt = tem; goto tail_recurse; }
3613 break;
3615 case Lisp_Cons:
3617 register Lisp_Object car, tem;
3619 /* A cons cell: three distinct cases.
3620 If first element is a string or a cons, process all the elements
3621 and effectively concatenate them.
3622 If first element is a negative number, truncate displaying cdr to
3623 at most that many characters. If positive, pad (with spaces)
3624 to at least that many characters.
3625 If first element is a symbol, process the cadr or caddr recursively
3626 according to whether the symbol's value is non-nil or nil. */
3627 car = XCONS (elt)->car;
3628 if (SYMBOLP (car))
3630 tem = Fboundp (car);
3631 elt = XCONS (elt)->cdr;
3632 if (!CONSP (elt))
3633 goto invalid;
3634 /* elt is now the cdr, and we know it is a cons cell.
3635 Use its car if CAR has a non-nil value. */
3636 if (!NILP (tem))
3638 tem = Fsymbol_value (car);
3639 if (!NILP (tem))
3640 { elt = XCONS (elt)->car; goto tail_recurse; }
3642 /* Symbol's value is nil (or symbol is unbound)
3643 Get the cddr of the original list
3644 and if possible find the caddr and use that. */
3645 elt = XCONS (elt)->cdr;
3646 if (NILP (elt))
3647 break;
3648 else if (!CONSP (elt))
3649 goto invalid;
3650 elt = XCONS (elt)->car;
3651 goto tail_recurse;
3653 else if (INTEGERP (car))
3655 register int lim = XINT (car);
3656 elt = XCONS (elt)->cdr;
3657 if (lim < 0)
3658 /* Negative int means reduce maximum width.
3659 DO NOT change MINENDCOL here!
3660 (20 -10 . foo) should truncate foo to 10 col
3661 and then pad to 20. */
3662 maxendcol = min (maxendcol, hpos - lim);
3663 else if (lim > 0)
3665 /* Padding specified. Don't let it be more than
3666 current maximum. */
3667 lim += hpos;
3668 if (lim > maxendcol)
3669 lim = maxendcol;
3670 /* If that's more padding than already wanted, queue it.
3671 But don't reduce padding already specified even if
3672 that is beyond the current truncation point. */
3673 if (lim > minendcol)
3674 minendcol = lim;
3676 goto tail_recurse;
3678 else if (STRINGP (car) || CONSP (car))
3680 register int limit = 50;
3681 /* LIMIT is to protect against circular lists. */
3682 while (CONSP (elt) && --limit > 0
3683 && hpos < maxendcol)
3685 hpos = display_mode_element (w, vpos, hpos, depth,
3686 hpos, maxendcol,
3687 XCONS (elt)->car);
3688 elt = XCONS (elt)->cdr;
3692 break;
3694 default:
3695 invalid:
3696 if (frame_title_ptr)
3697 hpos = store_frame_title ("*invalid*", minendcol, maxendcol);
3698 else
3699 hpos = display_string (w, vpos, "*invalid*", -1, hpos, 0, 1,
3700 minendcol, maxendcol);
3701 return hpos;
3704 if (minendcol > hpos)
3705 if (frame_title_ptr)
3706 hpos = store_frame_title ("", minendcol, maxendcol);
3707 else
3708 hpos = display_string (w, vpos, "", 0, hpos, 0, 1, minendcol, maxendcol);
3709 return hpos;
3712 /* Write a null-terminated, right justified decimal representation of
3713 the positive integer D to BUF using a minimal field width WIDTH. */
3715 static void
3716 pint2str (buf, width, d)
3717 register char *buf;
3718 register int width;
3719 register int d;
3721 register char *p = buf;
3723 if (d <= 0)
3724 *p++ = '0';
3725 else
3726 while (d > 0)
3728 *p++ = d % 10 + '0';
3729 d /= 10;
3731 for (width -= (int) (p - buf); width > 0; --width) *p++ = ' ';
3732 *p-- = '\0';
3733 while (p > buf)
3735 d = *buf;
3736 *buf++ = *p;
3737 *p-- = d;
3741 /* Return a string for the output of a mode line %-spec for window W,
3742 generated by character C. SPEC_WIDTH is the field width when
3743 padding to the left (%c, %l). The value returned from this
3744 function will later be truncated to width MAXWIDTH. */
3746 static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
3748 static char *
3749 decode_mode_spec (w, c, spec_width, maxwidth)
3750 struct window *w;
3751 register char c;
3752 register int spec_width;
3753 register int maxwidth;
3755 Lisp_Object obj;
3756 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
3757 char *decode_mode_spec_buf = (char *) FRAME_TEMP_GLYPHS (f)->total_contents;
3758 struct buffer *b = XBUFFER (w->buffer);
3760 obj = Qnil;
3761 if (maxwidth > FRAME_WIDTH (f))
3762 maxwidth = FRAME_WIDTH (f);
3764 switch (c)
3766 case '*':
3767 if (!NILP (b->read_only))
3768 return "%";
3769 if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
3770 return "*";
3771 return "-";
3773 case '+':
3774 /* This differs from %* only for a modified read-only buffer. */
3775 if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
3776 return "*";
3777 if (!NILP (b->read_only))
3778 return "%";
3779 return "-";
3781 case '&':
3782 /* This differs from %* in ignoring read-only-ness. */
3783 if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
3784 return "*";
3785 return "-";
3787 case '%':
3788 return "%";
3790 case '[':
3792 int i;
3793 char *p;
3795 if (command_loop_level > 5)
3796 return "[[[... ";
3797 p = decode_mode_spec_buf;
3798 for (i = 0; i < command_loop_level; i++)
3799 *p++ = '[';
3800 *p = 0;
3801 return decode_mode_spec_buf;
3804 case ']':
3806 int i;
3807 char *p;
3809 if (command_loop_level > 5)
3810 return " ...]]]";
3811 p = decode_mode_spec_buf;
3812 for (i = 0; i < command_loop_level; i++)
3813 *p++ = ']';
3814 *p = 0;
3815 return decode_mode_spec_buf;
3818 case '-':
3820 register char *p;
3821 register int i;
3823 if (maxwidth < sizeof (lots_of_dashes))
3824 return lots_of_dashes;
3825 else
3827 for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
3828 *p++ = '-';
3829 *p = '\0';
3831 return decode_mode_spec_buf;
3834 case 'b':
3835 obj = b->name;
3836 #if 0
3837 if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
3839 bcopy (XSTRING (obj)->data, decode_mode_spec_buf, maxwidth - 1);
3840 decode_mode_spec_buf[maxwidth - 1] = '\\';
3841 decode_mode_spec_buf[maxwidth] = '\0';
3842 return decode_mode_spec_buf;
3844 #endif
3845 break;
3847 case 'c':
3849 int col = current_column ();
3850 XSETFASTINT (w->column_number_displayed, col);
3851 pint2str (decode_mode_spec_buf, spec_width, col);
3852 return decode_mode_spec_buf;
3855 case 'F':
3856 /* %F displays the frame name. */
3857 if (!NILP (f->title))
3858 return (char *) XSTRING (f->title)->data;
3859 if (f->explicit_name || ! FRAME_WINDOW_P (f))
3860 return (char *) XSTRING (f->name)->data;
3861 return "Emacs";
3863 case 'f':
3864 obj = b->filename;
3865 #if 0
3866 if (NILP (obj))
3867 return "[none]";
3868 else if (STRINGP (obj) && XSTRING (obj)->size > maxwidth)
3870 bcopy ("...", decode_mode_spec_buf, 3);
3871 bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
3872 decode_mode_spec_buf + 3, maxwidth - 3);
3873 return decode_mode_spec_buf;
3875 #endif
3876 break;
3878 case 'l':
3880 int startpos = marker_position (w->start);
3881 int line, linepos, topline;
3882 int nlines, junk;
3883 Lisp_Object tem;
3884 int height = XFASTINT (w->height);
3886 /* If we decided that this buffer isn't suitable for line numbers,
3887 don't forget that too fast. */
3888 if (EQ (w->base_line_pos, w->buffer))
3889 goto no_value;
3890 /* But do forget it, if the window shows a different buffer now. */
3891 else if (BUFFERP (w->base_line_pos))
3892 w->base_line_pos = Qnil;
3894 /* If the buffer is very big, don't waste time. */
3895 if (BUF_ZV (b) - BUF_BEGV (b) > line_number_display_limit)
3897 w->base_line_pos = Qnil;
3898 w->base_line_number = Qnil;
3899 goto no_value;
3902 if (!NILP (w->base_line_number)
3903 && !NILP (w->base_line_pos)
3904 && XFASTINT (w->base_line_pos) <= marker_position (w->start))
3906 line = XFASTINT (w->base_line_number);
3907 linepos = XFASTINT (w->base_line_pos);
3909 else
3911 line = 1;
3912 linepos = BUF_BEGV (b);
3915 /* Count lines from base line to window start position. */
3916 nlines = display_count_lines (linepos, startpos, startpos, &junk);
3918 topline = nlines + line;
3920 /* Determine a new base line, if the old one is too close
3921 or too far away, or if we did not have one.
3922 "Too close" means it's plausible a scroll-down would
3923 go back past it. */
3924 if (startpos == BUF_BEGV (b))
3926 XSETFASTINT (w->base_line_number, topline);
3927 XSETFASTINT (w->base_line_pos, BUF_BEGV (b));
3929 else if (nlines < height + 25 || nlines > height * 3 + 50
3930 || linepos == BUF_BEGV (b))
3932 int limit = BUF_BEGV (b);
3933 int position;
3934 int distance = (height * 2 + 30) * 200;
3936 if (startpos - distance > limit)
3937 limit = startpos - distance;
3939 nlines = display_count_lines (startpos, limit,
3940 -(height * 2 + 30),
3941 &position);
3942 /* If we couldn't find the lines we wanted within
3943 200 chars per line,
3944 give up on line numbers for this window. */
3945 if (position == startpos - distance)
3947 w->base_line_pos = w->buffer;
3948 w->base_line_number = Qnil;
3949 goto no_value;
3952 XSETFASTINT (w->base_line_number, topline - nlines);
3953 XSETFASTINT (w->base_line_pos, position);
3956 /* Now count lines from the start pos to point. */
3957 nlines = display_count_lines (startpos, PT, PT, &junk);
3959 /* Record that we did display the line number. */
3960 line_number_displayed = 1;
3962 /* Make the string to show. */
3963 pint2str (decode_mode_spec_buf, spec_width, topline + nlines);
3964 return decode_mode_spec_buf;
3965 no_value:
3967 char* p = decode_mode_spec_buf;
3968 for (spec_width -= 2; spec_width > 0; --spec_width) *p++ = ' ';
3969 strcpy (p, "??");
3970 return decode_mode_spec_buf;
3973 break;
3975 case 'm':
3976 obj = b->mode_name;
3977 break;
3979 case 'n':
3980 if (BUF_BEGV (b) > BUF_BEG (b) || BUF_ZV (b) < BUF_Z (b))
3981 return " Narrow";
3982 break;
3984 case 'p':
3986 int pos = marker_position (w->start);
3987 int total = BUF_ZV (b) - BUF_BEGV (b);
3989 if (XFASTINT (w->window_end_pos) <= BUF_Z (b) - BUF_ZV (b))
3991 if (pos <= BUF_BEGV (b))
3992 return "All";
3993 else
3994 return "Bottom";
3996 else if (pos <= BUF_BEGV (b))
3997 return "Top";
3998 else
4000 if (total > 1000000)
4001 /* Do it differently for a large value, to avoid overflow. */
4002 total = ((pos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100);
4003 else
4004 total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total;
4005 /* We can't normally display a 3-digit number,
4006 so get us a 2-digit number that is close. */
4007 if (total == 100)
4008 total = 99;
4009 sprintf (decode_mode_spec_buf, "%2d%%", total);
4010 return decode_mode_spec_buf;
4014 /* Display percentage of size above the bottom of the screen. */
4015 case 'P':
4017 int toppos = marker_position (w->start);
4018 int botpos = BUF_Z (b) - XFASTINT (w->window_end_pos);
4019 int total = BUF_ZV (b) - BUF_BEGV (b);
4021 if (botpos >= BUF_ZV (b))
4023 if (toppos <= BUF_BEGV (b))
4024 return "All";
4025 else
4026 return "Bottom";
4028 else
4030 if (total > 1000000)
4031 /* Do it differently for a large value, to avoid overflow. */
4032 total = ((botpos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100);
4033 else
4034 total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total;
4035 /* We can't normally display a 3-digit number,
4036 so get us a 2-digit number that is close. */
4037 if (total == 100)
4038 total = 99;
4039 if (toppos <= BUF_BEGV (b))
4040 sprintf (decode_mode_spec_buf, "Top%2d%%", total);
4041 else
4042 sprintf (decode_mode_spec_buf, "%2d%%", total);
4043 return decode_mode_spec_buf;
4047 case 's':
4048 /* status of process */
4049 obj = Fget_buffer_process (w->buffer);
4050 if (NILP (obj))
4051 return "no process";
4052 #ifdef subprocesses
4053 obj = Fsymbol_name (Fprocess_status (obj));
4054 #endif
4055 break;
4057 case 't': /* indicate TEXT or BINARY */
4058 #ifdef MODE_LINE_BINARY_TEXT
4059 return MODE_LINE_BINARY_TEXT (b);
4060 #else
4061 return "T";
4062 #endif
4065 if (STRINGP (obj))
4066 return (char *) XSTRING (obj)->data;
4067 else
4068 return "";
4071 /* Search for COUNT instances of a line boundary, which means either a
4072 newline or (if selective display enabled) a carriage return.
4073 Start at START. If COUNT is negative, search backwards.
4075 If we find COUNT instances, set *SHORTAGE to zero, and return the
4076 position after the COUNTth match. Note that for reverse motion
4077 this is not the same as the usual convention for Emacs motion commands.
4079 If we don't find COUNT instances before reaching the end of the
4080 buffer (or the beginning, if scanning backwards), set *SHORTAGE to
4081 the number of line boundaries left unfound, and return the end of the
4082 buffer we bumped up against. */
4084 static int
4085 display_scan_buffer (start, count, shortage)
4086 int *shortage, start;
4087 register int count;
4089 int limit = ((count > 0) ? ZV - 1 : BEGV);
4090 int direction = ((count > 0) ? 1 : -1);
4092 register unsigned char *cursor;
4093 unsigned char *base;
4095 register int ceiling;
4096 register unsigned char *ceiling_addr;
4098 /* If we are not in selective display mode,
4099 check only for newlines. */
4100 if (! (!NILP (current_buffer->selective_display)
4101 && !INTEGERP (current_buffer->selective_display)))
4102 return scan_buffer ('\n', start, 0, count, shortage, 0);
4104 /* The code that follows is like scan_buffer
4105 but checks for either newline or carriage return. */
4107 if (shortage != 0)
4108 *shortage = 0;
4110 if (count > 0)
4111 while (start != limit + 1)
4113 ceiling = BUFFER_CEILING_OF (start);
4114 ceiling = min (limit, ceiling);
4115 ceiling_addr = &FETCH_CHAR (ceiling) + 1;
4116 base = (cursor = &FETCH_CHAR (start));
4117 while (1)
4119 while (*cursor != '\n' && *cursor != 015 && ++cursor != ceiling_addr)
4121 if (cursor != ceiling_addr)
4123 if (--count == 0)
4125 immediate_quit = 0;
4126 return (start + cursor - base + 1);
4128 else
4129 if (++cursor == ceiling_addr)
4130 break;
4132 else
4133 break;
4135 start += cursor - base;
4137 else
4139 start--; /* first character we scan */
4140 while (start > limit - 1)
4141 { /* we WILL scan under start */
4142 ceiling = BUFFER_FLOOR_OF (start);
4143 ceiling = max (limit, ceiling);
4144 ceiling_addr = &FETCH_CHAR (ceiling) - 1;
4145 base = (cursor = &FETCH_CHAR (start));
4146 cursor++;
4147 while (1)
4149 while (--cursor != ceiling_addr
4150 && *cursor != '\n' && *cursor != 015)
4152 if (cursor != ceiling_addr)
4154 if (++count == 0)
4156 immediate_quit = 0;
4157 return (start + cursor - base + 1);
4160 else
4161 break;
4163 start += cursor - base;
4167 if (shortage != 0)
4168 *shortage = count * direction;
4169 return (start + ((direction == 1 ? 0 : 1)));
4172 /* Count up to N lines starting from FROM.
4173 But don't go beyond LIMIT.
4174 Return the number of lines thus found (always positive).
4175 Store the position after what was found into *POS_PTR. */
4177 static int
4178 display_count_lines (from, limit, n, pos_ptr)
4179 int from, limit, n;
4180 int *pos_ptr;
4182 int oldbegv = BEGV;
4183 int oldzv = ZV;
4184 int shortage = 0;
4186 if (limit < from)
4187 BEGV = limit;
4188 else
4189 ZV = limit;
4191 *pos_ptr = display_scan_buffer (from, n, &shortage);
4193 ZV = oldzv;
4194 BEGV = oldbegv;
4196 if (n < 0)
4197 /* When scanning backwards, scan_buffer stops *after* the last newline
4198 it finds, but does count it. Compensate for that. */
4199 return - n - shortage - (*pos_ptr != limit);
4200 return n - shortage;
4203 /* Display STRING on one line of window W, starting at HPOS.
4204 Display at position VPOS. Caller should have done get_display_line.
4205 If VPOS == -1, display it as the current frame's title.
4206 LENGTH is the length of STRING, or -1 meaning STRING is null-terminated.
4208 TRUNCATE is GLYPH to display at end if truncated. Zero for none.
4210 MINCOL is the first column ok to end at. (Pad with spaces to this col.)
4211 MAXCOL is the last column ok to end at. Truncate here.
4212 -1 for MINCOL or MAXCOL means no explicit minimum or maximum.
4213 Both count from the left edge of the frame, as does HPOS.
4214 The right edge of W is an implicit maximum.
4215 If TRUNCATE is nonzero, the implicit maximum is one column before the edge.
4217 OBEY_WINDOW_WIDTH says to put spaces or vertical bars
4218 at the place where the current window ends in this line
4219 and not display anything beyond there. Otherwise, only MAXCOL
4220 controls where to stop output.
4222 Returns ending hpos. */
4224 static int
4225 display_string (w, vpos, string, length, hpos, truncate,
4226 obey_window_width, mincol, maxcol)
4227 struct window *w;
4228 unsigned char *string;
4229 int length;
4230 int vpos, hpos;
4231 GLYPH truncate;
4232 int obey_window_width;
4233 int mincol, maxcol;
4235 register int c;
4236 int truncated;
4237 register GLYPH *p1;
4238 int hscroll = XINT (w->hscroll);
4239 int tab_width = XINT (XBUFFER (w->buffer)->tab_width);
4240 register GLYPH *start;
4241 register GLYPH *end;
4242 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
4243 struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
4244 GLYPH *p1start = desired_glyphs->glyphs[vpos] + hpos;
4245 int window_width = XFASTINT (w->width);
4247 /* Use the standard display table, not the window's display table.
4248 We don't want the mode line in rot13. */
4249 register struct Lisp_Char_Table *dp = 0;
4250 int i;
4252 if (DISP_TABLE_P (Vstandard_display_table))
4253 dp = XCHAR_TABLE (Vstandard_display_table);
4255 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
4257 p1 = p1start;
4258 start = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
4260 if (obey_window_width)
4262 end = start + window_width - (truncate != 0);
4264 if (!WINDOW_RIGHTMOST_P (w))
4266 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
4268 int i;
4270 for (i = 0; i < FRAME_SCROLL_BAR_COLS (f); i++)
4271 *end-- = ' ';
4273 else if (!FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4274 *end-- = '|';
4278 if (! obey_window_width
4279 || (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol))
4280 end = desired_glyphs->glyphs[vpos] + maxcol;
4282 /* Store 0 in charstart for these columns. */
4283 for (i = (hpos >= 0 ? hpos : 0); i < end - p1start + hpos; i++)
4284 desired_glyphs->charstarts[vpos][i] = 0;
4286 if (maxcol >= 0 && mincol > maxcol)
4287 mincol = maxcol;
4289 /* We set truncated to 1 if we get stopped by trying to pass END
4290 (that is, trying to pass MAXCOL.) */
4291 truncated = 0;
4292 while (1)
4294 if (length == 0)
4295 break;
4296 c = *string++;
4297 /* Specified length. */
4298 if (length >= 0)
4299 length--;
4300 /* Unspecified length (null-terminated string). */
4301 else if (c == 0)
4302 break;
4304 if (p1 >= end)
4306 truncated = 1;
4307 break;
4310 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
4312 p1 = copy_part_of_rope (f, p1, start,
4313 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
4314 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
4317 else if (c >= 040 && c < 0177)
4319 if (p1 >= start)
4320 *p1 = c;
4321 p1++;
4323 else if (c == '\t')
4327 if (p1 >= start && p1 < end)
4328 *p1 = SPACEGLYPH;
4329 p1++;
4331 while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
4333 else if (c < 0200 && ! NILP (buffer_defaults.ctl_arrow))
4335 if (p1 >= start)
4336 *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
4337 ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
4339 p1++;
4340 if (p1 >= start && p1 < end)
4341 *p1 = c ^ 0100;
4342 p1++;
4344 else
4346 if (p1 >= start)
4347 *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
4348 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
4350 p1++;
4351 if (p1 >= start && p1 < end)
4352 *p1 = (c >> 6) + '0';
4353 p1++;
4354 if (p1 >= start && p1 < end)
4355 *p1 = (7 & (c >> 3)) + '0';
4356 p1++;
4357 if (p1 >= start && p1 < end)
4358 *p1 = (7 & c) + '0';
4359 p1++;
4363 if (truncated)
4365 p1 = end;
4366 if (truncate) *p1++ = fix_glyph (f, truncate, 0);
4368 else if (mincol >= 0)
4370 end = desired_glyphs->glyphs[vpos] + mincol;
4371 while (p1 < end)
4372 *p1++ = SPACEGLYPH;
4376 register int len = p1 - desired_glyphs->glyphs[vpos];
4378 if (len > desired_glyphs->used[vpos])
4379 desired_glyphs->used[vpos] = len;
4380 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
4382 return len;
4386 /* This is like a combination of memq and assq.
4387 Return 1 if PROPVAL appears as an element of LIST
4388 or as the car of an element of LIST.
4389 If PROPVAL is a list, compare each element against LIST
4390 in that way, and return 1 if any element of PROPVAL is found in LIST.
4391 Otherwise return 0.
4392 This function cannot quit. */
4395 invisible_p (propval, list)
4396 register Lisp_Object propval;
4397 Lisp_Object list;
4399 register Lisp_Object tail, proptail;
4400 for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
4402 register Lisp_Object tem;
4403 tem = XCONS (tail)->car;
4404 if (EQ (propval, tem))
4405 return 1;
4406 if (CONSP (tem) && EQ (propval, XCONS (tem)->car))
4407 return 1;
4409 if (CONSP (propval))
4410 for (proptail = propval; CONSP (proptail);
4411 proptail = XCONS (proptail)->cdr)
4413 Lisp_Object propelt;
4414 propelt = XCONS (proptail)->car;
4415 for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
4417 register Lisp_Object tem;
4418 tem = XCONS (tail)->car;
4419 if (EQ (propelt, tem))
4420 return 1;
4421 if (CONSP (tem) && EQ (propelt, XCONS (tem)->car))
4422 return 1;
4425 return 0;
4428 /* Return 1 if PROPVAL appears as the car of an element of LIST
4429 and the cdr of that element is non-nil.
4430 If PROPVAL is a list, check each element of PROPVAL in that way,
4431 and the first time some element is found,
4432 return 1 if the cdr of that element is non-nil.
4433 Otherwise return 0.
4434 This function cannot quit. */
4437 invisible_ellipsis_p (propval, list)
4438 register Lisp_Object propval;
4439 Lisp_Object list;
4441 register Lisp_Object tail, proptail;
4442 for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
4444 register Lisp_Object tem;
4445 tem = XCONS (tail)->car;
4446 if (CONSP (tem) && EQ (propval, XCONS (tem)->car))
4447 return ! NILP (XCONS (tem)->cdr);
4449 if (CONSP (propval))
4450 for (proptail = propval; CONSP (proptail);
4451 proptail = XCONS (proptail)->cdr)
4453 Lisp_Object propelt;
4454 propelt = XCONS (proptail)->car;
4455 for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
4457 register Lisp_Object tem;
4458 tem = XCONS (tail)->car;
4459 if (CONSP (tem) && EQ (propelt, XCONS (tem)->car))
4460 return ! NILP (XCONS (tem)->cdr);
4463 return 0;
4466 void
4467 syms_of_xdisp ()
4469 staticpro (&Qmenu_bar_update_hook);
4470 Qmenu_bar_update_hook = intern ("menu-bar-update-hook");
4472 staticpro (&Qoverriding_terminal_local_map);
4473 Qoverriding_terminal_local_map = intern ("overriding-terminal-local-map");
4475 staticpro (&Qoverriding_local_map);
4476 Qoverriding_local_map = intern ("overriding-local-map");
4478 staticpro (&Qwindow_scroll_functions);
4479 Qwindow_scroll_functions = intern ("window-scroll-functions");
4481 staticpro (&Qredisplay_end_trigger_functions);
4482 Qredisplay_end_trigger_functions = intern ("redisplay-end-trigger-functions");
4484 staticpro (&last_arrow_position);
4485 staticpro (&last_arrow_string);
4486 last_arrow_position = Qnil;
4487 last_arrow_string = Qnil;
4489 DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
4490 "String (or mode line construct) included (normally) in `mode-line-format'.");
4491 Vglobal_mode_string = Qnil;
4493 DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
4494 "Marker for where to display an arrow on top of the buffer text.\n\
4495 This must be the beginning of a line in order to work.\n\
4496 See also `overlay-arrow-string'.");
4497 Voverlay_arrow_position = Qnil;
4499 DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
4500 "String to display as an arrow. See also `overlay-arrow-position'.");
4501 Voverlay_arrow_string = Qnil;
4503 DEFVAR_INT ("scroll-step", &scroll_step,
4504 "*The number of lines to try scrolling a window by when point moves out.\n\
4505 If that fails to bring point back on frame, point is centered instead.\n\
4506 If this is zero, point is always centered after it moves off frame.");
4508 DEFVAR_INT ("scroll-conservatively", &scroll_conservatively,
4509 "*Scroll up to this many lines, to bring point back on screen.");
4510 scroll_conservatively = 0;
4512 DEFVAR_INT ("scroll-margin", &scroll_margin,
4513 "*Number of lines of margin at the top and bottom of a window.\n\
4514 Recenter the window whenever point gets within this many lines\n\
4515 of the top or bottom of the window.");
4516 scroll_margin = 0;
4518 DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
4520 DEFVAR_BOOL ("truncate-partial-width-windows",
4521 &truncate_partial_width_windows,
4522 "*Non-nil means truncate lines in all windows less than full frame wide.");
4523 truncate_partial_width_windows = 1;
4525 DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
4526 "*Non-nil means use inverse video for the mode line.");
4527 mode_line_inverse_video = 1;
4529 DEFVAR_INT ("line-number-display-limit", &line_number_display_limit,
4530 "*Maximum buffer size for which line number should be displayed.");
4531 line_number_display_limit = 1000000;
4533 DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
4534 "*Non-nil means highlight region even in nonselected windows.");
4535 highlight_nonselected_windows = 1;
4537 DEFVAR_BOOL ("multiple-frames", &multiple_frames,
4538 "Non-nil if more than one frame is visible on this display.\n\
4539 Minibuffer-only frames don't count, but iconified frames do.\n\
4540 This variable is not guaranteed to be accurate except while processing\n\
4541 `frame-title-format' and `icon-title-format'.");
4543 DEFVAR_LISP ("frame-title-format", &Vframe_title_format,
4544 "Template for displaying the titlebar of visible frames.\n\
4545 \(Assuming the window manager supports this feature.)\n\
4546 This variable has the same structure as `mode-line-format' (which see),\n\
4547 and is used only on frames for which no explicit name has been set\n\
4548 \(see `modify-frame-parameters').");
4549 DEFVAR_LISP ("icon-title-format", &Vicon_title_format,
4550 "Template for displaying the titlebar of an iconified frame.\n\
4551 \(Assuming the window manager supports this feature.)\n\
4552 This variable has the same structure as `mode-line-format' (which see),\n\
4553 and is used only on frames for which no explicit name has been set\n\
4554 \(see `modify-frame-parameters').");
4555 Vicon_title_format
4556 = Vframe_title_format
4557 = Fcons (intern ("multiple-frames"),
4558 Fcons (build_string ("%b"),
4559 Fcons (Fcons (build_string (""),
4560 Fcons (intern ("invocation-name"),
4561 Fcons (build_string ("@"),
4562 Fcons (intern ("system-name"),
4563 Qnil)))),
4564 Qnil)));
4566 DEFVAR_LISP ("message-log-max", &Vmessage_log_max,
4567 "Maximum number of lines to keep in the message log buffer.\n\
4568 If nil, disable message logging. If t, log messages but don't truncate\n\
4569 the buffer when it becomes large.");
4570 XSETFASTINT (Vmessage_log_max, 50);
4572 DEFVAR_LISP ("window-size-change-functions", &Vwindow_size_change_functions,
4573 "Functions called before redisplay, if window sizes have changed.\n\
4574 The value should be a list of functions that take one argument.\n\
4575 Just before redisplay, for each frame, if any of its windows have changed\n\
4576 size since the last redisplay, or have been split or deleted,\n\
4577 all the functions in the list are called, with the frame as argument.");
4578 Vwindow_size_change_functions = Qnil;
4580 DEFVAR_LISP ("window-scroll-functions", &Vwindow_scroll_functions,
4581 "List of Functions to call before redisplaying a window with scrolling.\n\
4582 Each function is called with two arguments, the window\n\
4583 and its new display-start position. Note that the value of `window-end'\n\
4584 is not valid when these functions are called.");
4585 Vwindow_scroll_functions = Qnil;
4588 /* initialize the window system */
4589 init_xdisp ()
4591 Lisp_Object root_window;
4592 #ifndef COMPILER_REGISTER_BUG
4593 register
4594 #endif /* COMPILER_REGISTER_BUG */
4595 struct window *mini_w;
4597 this_line_bufpos = 0;
4599 mini_w = XWINDOW (minibuf_window);
4600 root_window = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (mini_w)));
4602 echo_area_glyphs = 0;
4603 previous_echo_glyphs = 0;
4605 if (!noninteractive)
4607 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (root_window)));
4608 XSETFASTINT (XWINDOW (root_window)->top, 0);
4609 set_window_height (root_window, FRAME_HEIGHT (f) - 1, 0);
4610 XSETFASTINT (mini_w->top, FRAME_HEIGHT (f) - 1);
4611 set_window_height (minibuf_window, 1, 0);
4613 XSETFASTINT (XWINDOW (root_window)->width, FRAME_WIDTH (f));
4614 XSETFASTINT (mini_w->width, FRAME_WIDTH (f));