Initial revision
[emacs.git] / src / xdisp.c
blob82a92d5a689633cd16f2313ee346c3c9db6fb234
1 /* Display generation from window structure and buffer text.
2 Copyright (C) 1985, 1986, 1987, 1988 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
21 #include "config.h"
22 #include <stdio.h>
23 /*#include <ctype.h>*/
24 #undef NULL
25 #include "lisp.h"
26 #include "screen.h"
27 #include "window.h"
28 #include "termchar.h"
29 #include "dispextern.h"
30 #include "buffer.h"
31 #include "indent.h"
32 #include "commands.h"
33 #include "macros.h"
34 #include "disptab.h"
36 extern int interrupt_input;
37 extern int command_loop_level;
39 /* Nonzero means print newline before next minibuffer message. */
41 int noninteractive_need_newline;
43 #define min(a, b) ((a) < (b) ? (a) : (b))
44 #define max(a, b) ((a) > (b) ? (a) : (b))
46 /* The buffer position of the first character appearing
47 entirely or partially on the current screen line.
48 Or zero, which disables the optimization for the current screen line. */
49 static int this_line_bufpos;
51 /* Number of characters past the end of this line,
52 including the terminating newline */
53 static int this_line_endpos;
55 /* The vertical position of this screen line. */
56 static int this_line_vpos;
58 /* Hpos value for start of display on this screen line.
59 Usually zero, but negative if first character really began
60 on previous line */
61 static int this_line_start_hpos;
63 /* Buffer that this_line variables are describing. */
64 static struct buffer *this_line_buffer;
66 /* Set by try_window_id to the vpos of first of any lines
67 scrolled on to the bottom of the screen. These lines should
68 not be included in any general scroll computation. */
69 static int scroll_bottom_vpos;
71 /* Value of echo_area_glyphs when it was last acted on.
72 If this is nonzero, there is a message on the screen
73 in the minibuffer and it should be erased as soon
74 as it is no longer requested to appear. */
75 char *previous_echo_glyphs;
77 /* Nonzero means truncate lines in all windows less wide than the screen */
78 int truncate_partial_width_windows;
80 Lisp_Object Vglobal_mode_string;
82 /* Marker for where to display an arrow on top of the buffer text. */
83 Lisp_Object Voverlay_arrow_position;
85 /* String to display for the arrow. */
86 Lisp_Object Voverlay_arrow_string;
88 /* Values of those variables at last redisplay. */
89 Lisp_Object last_arrow_position, last_arrow_string;
91 /* Nonzero if overlay arrow has been displayed once in this window. */
92 static int overlay_arrow_seen;
94 /* If cursor motion alone moves point off screen,
95 Try scrolling this many lines up or down if that will bring it back. */
96 int scroll_step;
98 /* Nonzero if try_window_id has made blank lines at window bottom
99 since the last redisplay that paused */
100 static int blank_end_of_window;
102 /* Number of windows showing the buffer of the selected window.
103 keyboard.c refers to this. */
104 int buffer_shared;
106 /* display_text_line sets these to the screen position (origin 0) of point,
107 whether the window is selected or not.
108 Set one to -1 first to determine whether point was found afterwards. */
110 static int cursor_vpos;
111 static int cursor_hpos;
113 int debug_end_pos;
115 /* Nonzero means display mode line highlighted */
116 int mode_line_inverse_video;
118 static void echo_area_display ();
119 void mark_window_display_accurate ();
120 static void redisplay_windows ();
121 static void redisplay_window ();
122 static void try_window ();
123 static int try_window_id ();
124 static struct position *display_text_line ();
125 static void display_mode_line ();
126 static int display_mode_element ();
127 static char *fmodetrunc ();
128 static char *decode_mode_spec ();
129 static int display_string ();
131 /* Prompt to display in front of the minibuffer contents */
132 char *minibuf_prompt;
134 /* Width in columns of current minibuffer prompt. */
135 int minibuf_prompt_width;
137 /* Message to display instead of minibuffer contents
138 This is what the functions error and message make,
139 and command echoing uses it as well.
140 It overrides the minibuf_prompt as well as the buffer. */
141 char *echo_area_glyphs;
143 /* true iff we should redraw the mode lines on the next redisplay */
144 int update_mode_lines;
146 /* Smallest number of characters before the gap
147 at any time since last redisplay that finished.
148 Valid for current buffer when try_window_id can be called. */
149 int beg_unchanged;
151 /* Smallest number of characters after the gap
152 at any time since last redisplay that finished.
153 Valid for current buffer when try_window_id can be called. */
154 int end_unchanged;
156 /* MODIFF as of last redisplay that finished;
157 if it matches MODIFF, beg_unchanged and end_unchanged
158 contain no useful information */
159 int unchanged_modified;
161 /* Nonzero if head_clip or tail_clip of current buffer has changed
162 since last redisplay that finished */
163 int clip_changed;
165 /* Nonzero if window sizes or contents have changed
166 since last redisplay that finished */
167 int windows_or_buffers_changed;
170 #ifndef MULTI_SCREEN
172 DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "",
173 "Clear the screen and output again what is supposed to appear on it.")
176 if (screen_height == 0) abort (); /* Some bug zeros some core */
177 clear_screen ();
178 fflush (stdout);
179 clear_screen_records ();
180 if (screen_height == 0) abort (); /* Some bug zeros some core */
181 windows_or_buffers_changed++;
182 /* Mark all windows as INaccurate,
183 so that every window will have its redisplay done. */
184 mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 0);
185 if (screen_height == 0) abort (); /* Some bug zeros some core */
186 return Qnil;
189 #endif /* not MULTI_SCREEN */
191 /* Buffer used for messages formatted by `message'. */
192 char *message_buf;
194 /* Nonzero if message_buf is being used by print;
195 zero if being used by message. */
196 int message_buf_print;
198 /* dump an informative message to the minibuf */
199 /* VARARGS 1 */
201 void
202 message (m, a1, a2, a3)
203 char *m;
205 if (noninteractive)
207 if (noninteractive_need_newline)
208 putc ('\n', stderr);
209 noninteractive_need_newline = 0;
210 fprintf (stderr, m, a1, a2, a3);
211 fprintf (stderr, "\n");
212 fflush (stderr);
214 /* A null message buffer means that the screen hasn't really been
215 initialized yet. Error messages get reported properly by
216 cmd_error, so this must be just an informative message; toss it. */
217 else if (INTERACTIVE && SCREEN_MESSAGE_BUF (selected_screen))
219 #ifdef MULTI_SCREEN
220 choose_minibuf_screen ();
221 Fmake_screen_visible (WINDOW_SCREEN (XWINDOW (minibuf_window)));
222 #endif
225 #ifdef NO_ARG_ARRAY
226 int a[3];
227 a[0] = a1;
228 a[1] = a2;
229 a[2] = a3;
231 doprnt (SCREEN_MESSAGE_BUF (selected_screen),
232 SCREEN_WIDTH (selected_screen), m, 0, 3, a);
233 #else
234 doprnt (SCREEN_MESSAGE_BUF (selected_screen),
235 SCREEN_WIDTH (selected_screen), m, 0, 3, &a1);
236 #endif /* NO_ARG_ARRAY */
239 echo_area_glyphs = SCREEN_MESSAGE_BUF (selected_screen);
241 /* Print should start at the beginning of the message
242 buffer next time. */
243 message_buf_print = 0;
245 do_pending_window_change ();
246 echo_area_display ();
247 update_screen (XSCREEN (XWINDOW (minibuf_window)->screen), 1, 1);
248 do_pending_window_change ();
252 /* Specify m, a string, as a message in the minibuf. */
253 void
254 message1 (m)
255 char *m;
257 if (noninteractive)
259 if (noninteractive_need_newline)
260 putc ('\n', stderr);
261 noninteractive_need_newline = 0;
262 fprintf (stderr, "%s\n", m);
263 fflush (stderr);
265 /* A null message buffer means that the screen hasn't really been
266 initialized yet. Error messages get reported properly by
267 cmd_error, so this must be just an informative message; toss it. */
268 else if (INTERACTIVE && SCREEN_MESSAGE_BUF (selected_screen))
270 #ifdef MULTI_SCREEN
271 choose_minibuf_screen ();
272 Fmake_screen_visible (WINDOW_SCREEN (XWINDOW (minibuf_window)));
273 #endif
275 echo_area_glyphs = m;
276 do_pending_window_change ();
277 echo_area_display ();
278 update_screen (XSCREEN (XWINDOW (minibuf_window)->screen), 1, 1);
279 do_pending_window_change ();
283 static void
284 echo_area_display ()
286 register int vpos;
287 SCREEN_PTR s;
289 #ifdef MULTI_SCREEN
290 choose_minibuf_screen ();
291 s = XSCREEN (WINDOW_SCREEN (XWINDOW (minibuf_window)));
293 if (! SCREEN_VISIBLE_P (s))
294 return;
295 #endif
297 if (screen_garbaged)
299 Fredraw_display ();
300 screen_garbaged = 0;
303 if (echo_area_glyphs || minibuf_level == 0)
305 vpos = XFASTINT (XWINDOW (minibuf_window)->top);
306 get_display_line (s, vpos, 0);
307 display_string (XWINDOW (minibuf_window), vpos,
308 echo_area_glyphs ? echo_area_glyphs : "",
309 0, 0, 0, SCREEN_WIDTH (s));
311 /* If desired cursor location is on this line, put it at end of text */
312 if (SCREEN_CURSOR_Y (s) == vpos)
313 SCREEN_CURSOR_X (s) = s->desired_glyphs->used[vpos];
315 else if (!EQ (minibuf_window, selected_window))
316 windows_or_buffers_changed++;
318 if (EQ (minibuf_window, selected_window))
319 this_line_bufpos = 0;
321 previous_echo_glyphs = echo_area_glyphs;
324 /* Do a screen update, taking possible shortcuts into account.
325 This is the main external entry point for redisplay.
327 If the last redisplay displayed an echo area message and that
328 message is no longer requested, we clear the echo area
329 or bring back the minibuffer if that is in use.
331 Everyone would like to have a hook here to call eval,
332 but that cannot be done safely without a lot of changes elsewhere.
333 This can be called from signal handlers; with alarms set up;
334 or with synchronous processes running.
335 See the function `echo' in keyboard.c.
336 See Fcall_process; if you called it from here, it could be
337 entered recursively. */
339 void
340 redisplay ()
342 register struct window *w = XWINDOW (selected_window);
343 register int pause;
344 int must_finish = 0;
345 int all_windows;
346 register int tlbufpos, tlendpos;
347 struct position pos;
348 extern int input_pending;
350 if (noninteractive)
351 return;
353 /* Notice any pending interrupt request to change screen size. */
354 do_pending_window_change ();
356 if (screen_garbaged)
358 Fredraw_display ();
359 screen_garbaged = 0;
362 /* Normally the message* functions will have already displayed and
363 updated the echo area, but the screen may have been trashed, or
364 the update may have been preempted, so display the echo area
365 again here. */
366 if (echo_area_glyphs || previous_echo_glyphs)
368 echo_area_display ();
369 must_finish = 1;
372 if (clip_changed || windows_or_buffers_changed)
373 update_mode_lines++;
375 /* Detect case that we need to write a star in the mode line. */
376 if (XFASTINT (w->last_modified) < MODIFF
377 && XFASTINT (w->last_modified) <= current_buffer->save_modified)
379 w->update_mode_line = Qt;
380 if (buffer_shared > 1)
381 update_mode_lines++;
384 SCREEN_SCROLL_BOTTOM_VPOS (XSCREEN (w->screen)) = -1;
386 all_windows = update_mode_lines || buffer_shared > 1;
388 /* If specs for an arrow have changed, do thorough redisplay
389 to ensure we remove any arrow that should no longer exist. */
390 if (Voverlay_arrow_position != last_arrow_position
391 || Voverlay_arrow_string != last_arrow_string)
392 all_windows = 1, clip_changed = 1;
394 tlbufpos = this_line_bufpos;
395 tlendpos = this_line_endpos;
396 if (!all_windows && tlbufpos > 0 && NILP (w->update_mode_line)
397 && SCREEN_VISIBLE_P (XSCREEN (w->screen))
398 /* Make sure recorded data applies to current buffer, etc */
399 && this_line_buffer == current_buffer
400 && current_buffer == XBUFFER (w->buffer)
401 && NILP (w->force_start)
402 /* Point must be on the line that we have info recorded about */
403 && point >= tlbufpos
404 && point <= Z - tlendpos
405 /* All text outside that line, including its final newline,
406 must be unchanged */
407 && (XFASTINT (w->last_modified) >= MODIFF
408 || (beg_unchanged >= tlbufpos - 1
409 && GPT >= tlbufpos
410 /* If selective display, can't optimize
411 if the changes start at the beginning of the line. */
412 && ((XTYPE (current_buffer->selective_display) == Lisp_Int
413 && XINT (current_buffer->selective_display) > 0
414 ? (beg_unchanged >= tlbufpos
415 && GPT > tlbufpos)
416 : 1))
417 && end_unchanged >= tlendpos
418 && Z - GPT >= tlendpos)))
420 if (tlbufpos > BEGV && FETCH_CHAR (tlbufpos - 1) != '\n'
421 && (tlbufpos == ZV
422 || FETCH_CHAR (tlbufpos) == '\n'))
423 /* Former continuation line has disappeared by becoming empty */
424 goto cancel;
425 else if (XFASTINT (w->last_modified) < MODIFF
426 || MINI_WINDOW_P (w))
428 cursor_vpos = -1;
429 overlay_arrow_seen = 0;
430 display_text_line (w, tlbufpos, this_line_vpos, this_line_start_hpos,
431 pos_tab_offset (w, tlbufpos));
432 /* If line contains point, is not continued,
433 and ends at same distance from eob as before, we win */
434 if (cursor_vpos >= 0 && this_line_bufpos
435 && this_line_endpos == tlendpos)
437 if (XFASTINT (w->width) != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w))))
438 preserve_other_columns (w);
439 goto update;
441 else
442 goto cancel;
444 else if (point == XFASTINT (w->last_point))
446 if (!must_finish)
448 do_pending_window_change ();
449 return;
451 goto update;
453 else
455 pos = *compute_motion (tlbufpos, 0,
456 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
457 point, 2, - (1 << (SHORTBITS - 1)),
458 XFASTINT (w->width) - 1
459 - (XFASTINT (w->width) + XFASTINT (w->left)
460 != SCREEN_WIDTH (selected_screen)),
461 XINT (w->hscroll), 0);
462 if (pos.vpos < 1)
464 SCREEN_CURSOR_X (selected_screen)
465 = XFASTINT (w->left) + max (pos.hpos, 0);
466 SCREEN_CURSOR_Y (selected_screen) = this_line_vpos;
467 goto update;
469 else
470 goto cancel;
472 cancel:
473 /* Text changed drastically or point moved off of line */
474 cancel_line (this_line_vpos, selected_screen);
477 this_line_bufpos = 0;
478 all_windows |= buffer_shared > 1;
480 if (all_windows)
482 #ifdef MULTI_SCREEN
483 Lisp_Object tail;
485 /* Recompute # windows showing selected buffer.
486 This will be incremented each time such a window is displayed. */
487 buffer_shared = 0;
489 for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr)
491 SCREEN_PTR s;
493 if (XTYPE (XCONS (tail)->car) != Lisp_Screen)
494 continue;
496 s = XSCREEN (XCONS (tail)->car);
497 if (s->visible)
498 /* Redraw its windows. */
499 redisplay_windows (SCREEN_ROOT_WINDOW (s));
501 #else
502 redisplay_windows (SCREEN_ROOT_WINDOW (s));
503 #endif /* not MULTI_SCREEN */
505 else if (SCREEN_VISIBLE_P (selected_screen))
507 redisplay_window (selected_window, 1);
508 if (XFASTINT (w->width) != SCREEN_WIDTH (selected_screen))
509 preserve_other_columns (w);
512 update:
513 /* Prevent various kinds of signals during display update.
514 stdio is not robust about handling signals,
515 which can cause an apparent I/O error. */
516 if (interrupt_input)
517 unrequest_sigio ();
518 stop_polling ();
520 #ifdef MULTI_SCREEN
521 if (all_windows)
523 Lisp_Object tail;
525 pause = 0;
527 for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr)
529 SCREEN_PTR s;
531 if (XTYPE (XCONS (tail)->car) != Lisp_Screen)
532 continue;
534 s = XSCREEN (XCONS (tail)->car);
535 if (s->visible)
537 pause |= update_screen (s, 0, 0);
538 if (!pause)
539 mark_window_display_accurate (s->root_window, 1);
543 else
544 #endif /* MULTI_SCREEN */
546 if (SCREEN_VISIBLE_P (selected_screen))
547 pause = update_screen (selected_screen, 0, 0);
548 #ifdef MULTI_SCREEN
549 /* We may have called echo_area_display at the top of this
550 function. If the echo area is on another screen, that may
551 have put text on a screen other than the selected one, so the
552 above call to update_screen would not have caught it. Catch
553 it here. */
555 SCREEN_PTR mini_screen =
556 XSCREEN (WINDOW_SCREEN (XWINDOW (minibuf_window)));
558 if (mini_screen != selected_screen)
559 pause |= update_screen (mini_screen, 0, 0);
561 #endif
564 /* If screen does not match, prevent doing single-line-update next time.
565 Also, don't forget to check every line to update the arrow. */
566 if (pause)
568 this_line_bufpos = 0;
569 if (!NILP (last_arrow_position))
571 last_arrow_position = Qt;
572 last_arrow_string = Qt;
574 /* If we pause after scrolling, some lines in current_screen
575 may be null, so preserve_other_columns won't be able to
576 preserve all the vertical-bar separators. So, avoid using it
577 in that case. */
578 if (XFASTINT (w->width) != SCREEN_WIDTH (selected_screen))
579 update_mode_lines = 1;
582 /* Now text on screen agrees with windows, so
583 put info into the windows for partial redisplay to follow */
585 if (!pause)
587 register struct buffer *b = XBUFFER (w->buffer);
589 blank_end_of_window = 0;
590 clip_changed = 0;
591 unchanged_modified = BUF_MODIFF (b);
592 beg_unchanged = BUF_GPT (b) - BUF_BEG (b);
593 end_unchanged = BUF_Z (b) - BUF_GPT (b);
595 XFASTINT (w->last_point) = BUF_PT (b);
596 XFASTINT (w->last_point_x) = SCREEN_CURSOR_X (selected_screen);
597 XFASTINT (w->last_point_y) = SCREEN_CURSOR_Y (selected_screen);
599 if (all_windows)
600 mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 1);
601 else
603 w->update_mode_line = Qnil;
604 XFASTINT (w->last_modified) = BUF_MODIFF (b);
605 w->window_end_valid = Qt;
606 last_arrow_position = Voverlay_arrow_position;
607 last_arrow_string = Voverlay_arrow_string;
609 update_mode_lines = 0;
610 windows_or_buffers_changed = 0;
613 /* Start SIGIO interrupts coming again.
614 Having them off during the code above
615 makes it less likely one will discard output,
616 but not impossible, since there might be stuff
617 in the system buffer here.
618 But it is much hairier to try to do anything about that. */
620 if (interrupt_input)
621 request_sigio ();
622 start_polling ();
624 /* Change screen size now if a change is pending. */
625 do_pending_window_change ();
628 /* Redisplay, but leave alone any recent echo area message
629 unless another message has been requested in its place.
631 This is useful in situations where you need to redisplay but no
632 user action has occurred, making it inappropriate for the message
633 area to be cleared. See tracking_off and
634 wait_reading_process_input for examples of these situations. */
636 redisplay_preserve_echo_area ()
638 if (echo_area_glyphs == 0 && previous_echo_glyphs != 0)
640 echo_area_glyphs = previous_echo_glyphs;
641 redisplay ();
642 echo_area_glyphs = 0;
644 else
645 redisplay ();
648 void
649 mark_window_display_accurate (window, flag)
650 Lisp_Object window;
651 int flag;
653 register struct window *w;
655 for (;!NILP (window); window = w->next)
657 w = XWINDOW (window);
659 if (!NILP (w->buffer))
660 XFASTINT (w->last_modified)
661 = !flag ? 0
662 : XBUFFER (w->buffer) == current_buffer
663 ? MODIFF : BUF_MODIFF (XBUFFER (w->buffer));
664 w->window_end_valid = Qt;
665 w->update_mode_line = Qnil;
667 if (!NILP (w->vchild))
668 mark_window_display_accurate (w->vchild, flag);
669 if (!NILP (w->hchild))
670 mark_window_display_accurate (w->hchild, flag);
673 if (flag)
675 last_arrow_position = Voverlay_arrow_position;
676 last_arrow_string = Voverlay_arrow_string;
678 else
680 /* t is unequal to any useful value of Voverlay_arrow_... */
681 last_arrow_position = Qt;
682 last_arrow_string = Qt;
686 int do_id = 1;
688 static void
689 redisplay_windows (window)
690 Lisp_Object window;
692 for (; !NILP (window); window = XWINDOW (window)->next)
693 redisplay_window (window, 0);
696 static void
697 redisplay_window (window, just_this_one)
698 Lisp_Object window;
699 int just_this_one;
701 register struct window *w = XWINDOW (window);
702 SCREEN_PTR s = XSCREEN (w->screen);
703 int height;
704 register int lpoint = point;
705 struct buffer *old = current_buffer;
706 register int width = XFASTINT (w->width) - 1
707 - (XFASTINT (w->width) + XFASTINT (w->left)
708 != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w))));
709 register int startp;
710 register int hscroll = XINT (w->hscroll);
711 struct position pos;
712 int opoint;
713 int tem;
714 int window_needs_modeline;
716 if (SCREEN_HEIGHT (s) == 0) abort (); /* Some bug zeros some core */
718 /* If this is a combination window, do its children; that's all. */
720 if (!NILP (w->vchild))
722 redisplay_windows (w->vchild);
723 return;
725 if (!NILP (w->hchild))
727 redisplay_windows (w->hchild);
728 return;
730 if (NILP (w->buffer))
731 abort ();
733 height = window_internal_height (w);
735 if (MINI_WINDOW_P (w))
737 if (w == XWINDOW (minibuf_window))
739 if (echo_area_glyphs)
740 /* We've already displayed the echo area glyphs, if any. */
741 return;
743 else
745 /* This is a minibuffer, but it's not the currently active one, so
746 clear it. */
747 int vpos = XFASTINT (XWINDOW (SCREEN_MINIBUF_WINDOW (s))->top);
748 int i;
750 for (i = 0; i < height; i++)
752 get_display_line (s, vpos + i, 0);
753 display_string (w, vpos + i, "", 0, 0, 0, width);
756 return;
760 if (update_mode_lines)
761 w->update_mode_line = Qt;
763 /* Otherwise set up data on this window; select its buffer and point value */
765 current_buffer = XBUFFER (w->buffer);
766 opoint = point;
768 /* Count number of windows showing the selected buffer. */
770 if (!just_this_one
771 && current_buffer == XBUFFER (XWINDOW (selected_window)->buffer))
772 buffer_shared++;
774 /* POINT refers normally to the selected window.
775 For any other window, set up appropriate value. */
777 if (!EQ (window, selected_window))
779 SET_PT (marker_position (w->pointm));
780 if (point < BEGV)
782 SET_PT (BEGV);
783 Fset_marker (w->pointm, make_number (point), Qnil);
785 else if (point > (ZV - 1))
787 SET_PT (ZV);
788 Fset_marker (w->pointm, make_number (point), Qnil);
792 /* If window-start is screwed up, choose a new one. */
793 if (XMARKER (w->start)->buffer != current_buffer)
794 goto recenter;
796 startp = marker_position (w->start);
798 /* Handle case where place to start displaying has been specified,
799 unless the specified location is outside the visible range. */
800 if (!NILP (w->force_start))
802 w->update_mode_line = Qt;
803 w->force_start = Qnil;
804 XFASTINT (w->last_modified) = 0;
805 if (startp < BEGV) startp = BEGV;
806 if (startp > ZV) startp = ZV;
807 try_window (window, startp);
808 if (cursor_vpos < 0)
810 /* If point does not appear, move point so it does appear */
811 pos = *compute_motion (startp, 0,
812 ((EQ (window, minibuf_window) && startp == 1)
813 ? minibuf_prompt_width : 0)
815 (hscroll ? 1 - hscroll : 0),
816 ZV, height / 2,
817 - (1 << (SHORTBITS - 1)),
818 width, hscroll, pos_tab_offset (w, startp));
819 SET_PT (pos.bufpos);
820 if (w != XWINDOW (SCREEN_SELECTED_WINDOW (s)))
821 Fset_marker (w->pointm, make_number (point), Qnil);
822 else
824 lpoint = point;
825 SCREEN_CURSOR_X (s) = max (0, pos.hpos) + XFASTINT (w->left);
826 SCREEN_CURSOR_Y (s) = pos.vpos + XFASTINT (w->top);
829 goto done;
832 /* Handle case where text has not changed, only point,
833 and it has not moved off the screen */
835 /* This code is not used for minibuffer for the sake of
836 the case of redisplaying to replace an echo area message;
837 since in that case the minibuffer contents per se are usually unchanged.
838 This code is of no real use in the minibuffer since
839 the handling of this_line_bufpos, etc.,
840 in redisplay handles the same cases. */
842 if (XFASTINT (w->last_modified) >= MODIFF
843 && point >= startp && !clip_changed
844 && (just_this_one || XFASTINT (w->width) == SCREEN_WIDTH (s))
845 && !EQ (window, minibuf_window))
847 pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
848 point, height + 1, 10000, width, hscroll,
849 pos_tab_offset (w, startp));
851 if (pos.vpos < height)
853 /* Ok, point is still on screen */
854 if (w == XWINDOW (SCREEN_SELECTED_WINDOW (s)))
856 /* These variables are supposed to be origin 1 */
857 SCREEN_CURSOR_X (s) = max (0, pos.hpos) + XFASTINT (w->left);
858 SCREEN_CURSOR_Y (s) = pos.vpos + XFASTINT (w->top);
860 /* This doesn't do the trick, because if a window to the right of
861 this one must be redisplayed, this does nothing because there
862 is nothing in DesiredScreen yet, and then the other window is
863 redisplayed, making likes that are empty in this window's columns.
864 if (XFASTINT (w->width) != SCREEN_WIDTH (s))
865 preserve_my_columns (w);
867 goto done;
869 /* Don't bother trying redisplay with same start;
870 we already know it will lose */
872 /* If current starting point was originally the beginning of a line
873 but no longer is, find a new starting point. */
874 else if (!NILP (w->start_at_line_beg)
875 && !(startp == BEGV
876 || FETCH_CHAR (startp - 1) == '\n'))
878 goto recenter;
880 else if (just_this_one && !MINI_WINDOW_P (w)
881 && point >= startp
882 && XFASTINT (w->last_modified)
883 && ! EQ (w->window_end_valid, Qnil)
884 && do_id && !clip_changed
885 && !blank_end_of_window
886 && XFASTINT (w->width) == SCREEN_WIDTH (s)
887 && EQ (last_arrow_position, Voverlay_arrow_position)
888 && EQ (last_arrow_string, Voverlay_arrow_string)
889 && (tem = try_window_id (SCREEN_SELECTED_WINDOW (s)))
890 && tem != -2)
892 /* tem > 0 means success. tem == -1 means choose new start.
893 tem == -2 means try again with same start,
894 and nothing but whitespace follows the changed stuff.
895 tem == 0 means try again with same start. */
896 if (tem > 0)
897 goto done;
899 else if (startp >= BEGV && startp <= ZV
900 /* Avoid starting display at end of buffer! */
901 && (startp < ZV || startp == BEGV
902 || (XFASTINT (w->last_modified) >= MODIFF)))
904 /* Try to redisplay starting at same place as before */
905 /* If point has not moved off screen, accept the results */
906 try_window (window, startp);
907 if (cursor_vpos >= 0)
908 goto done;
909 else
910 cancel_my_columns (w);
913 XFASTINT (w->last_modified) = 0;
914 w->update_mode_line = Qt;
916 /* Try to scroll by specified few lines */
918 if (scroll_step && !clip_changed)
920 if (point > startp)
922 pos = *vmotion (Z - XFASTINT (w->window_end_pos),
923 scroll_step, width, hscroll, window);
924 if (pos.vpos >= height)
925 goto scroll_fail;
928 pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step,
929 width, hscroll, window);
931 if (point >= pos.bufpos)
933 try_window (window, pos.bufpos);
934 if (cursor_vpos >= 0)
935 goto done;
936 else
937 cancel_my_columns (w);
939 scroll_fail: ;
942 /* Finally, just choose place to start which centers point */
944 recenter:
945 pos = *vmotion (point, - height / 2, width, hscroll, window);
946 try_window (window, pos.bufpos);
948 startp = marker_position (w->start);
949 w->start_at_line_beg =
950 (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
952 done:
953 /* If window not full width, must redo its mode line
954 if the window to its side is being redone */
955 if ((!NILP (w->update_mode_line)
956 || (!just_this_one && width < SCREEN_WIDTH (s) - 1))
957 && height != XFASTINT (w->height))
958 display_mode_line (w);
960 SET_PT (opoint);
961 current_buffer = old;
962 SET_PT (lpoint);
965 /* Do full redisplay on one window, starting at position `pos'. */
967 static void
968 try_window (window, pos)
969 Lisp_Object window;
970 register int pos;
972 register struct window *w = XWINDOW (window);
973 register int height = window_internal_height (w);
974 register int vpos = XFASTINT (w->top);
975 register int last_text_vpos = vpos;
976 int tab_offset = pos_tab_offset (w, pos);
977 SCREEN_PTR s = XSCREEN (w->screen);
978 int width = XFASTINT (w->width) - 1
979 - (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s));
980 struct position val;
982 Fset_marker (w->start, make_number (pos), Qnil);
983 cursor_vpos = -1;
984 overlay_arrow_seen = 0;
985 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
987 while (--height >= 0)
989 val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
990 tab_offset += width;
991 if (val.vpos) tab_offset = 0;
992 vpos++;
993 if (pos != val.bufpos)
994 last_text_vpos
995 /* Next line, unless prev line ended in end of buffer with no cr */
996 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
997 pos = val.bufpos;
1000 /* If last line is continued in middle of character,
1001 include the split character in the text considered on the screen */
1002 if (val.hpos < (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
1003 pos++;
1005 /* If bottom just moved off end of screen, change mode line percentage. */
1006 if (XFASTINT (w->window_end_pos) == 0
1007 && Z != pos)
1008 w->update_mode_line = Qt;
1010 /* Say where last char on screen will be, once redisplay is finished. */
1011 XFASTINT (w->window_end_pos) = Z - pos;
1012 XFASTINT (w->window_end_vpos) = last_text_vpos - XFASTINT (w->top);
1013 /* But that is not valid info until redisplay finishes. */
1014 w->window_end_valid = Qnil;
1017 /* Try to redisplay when buffer is modified locally,
1018 computing insert/delete line to preserve text outside
1019 the bounds of the changes.
1020 Return 1 if successful, 0 if if cannot tell what to do,
1021 or -1 to tell caller to find a new window start,
1022 or -2 to tell caller to do normal redisplay with same window start. */
1024 static int
1025 try_window_id (window)
1026 Lisp_Object window;
1028 int pos;
1029 register struct window *w = XWINDOW (window);
1030 register int height = window_internal_height (w);
1031 SCREEN_PTR s = XSCREEN (w->screen);
1032 int top = XFASTINT (w->top);
1033 int start = marker_position (w->start);
1034 int width = XFASTINT (w->width) - 1
1035 - (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s));
1036 int hscroll = XINT (w->hscroll);
1037 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
1038 register int vpos;
1039 register int i, tem;
1040 int last_text_vpos = 0;
1041 int stop_vpos;
1043 struct position val, bp, ep, xp, pp;
1044 int scroll_amount = 0;
1045 int delta;
1046 int tab_offset, epto;
1048 if (GPT - BEG < beg_unchanged)
1049 beg_unchanged = GPT - BEG;
1050 if (Z - GPT < end_unchanged)
1051 end_unchanged = Z - GPT;
1053 if (beg_unchanged + 1 < start)
1054 return 0; /* Give up if changes go above top of window */
1056 /* Find position before which nothing is changed. */
1057 bp = *compute_motion (start, 0, lmargin,
1058 beg_unchanged + 1, height + 1, 0, width, hscroll,
1059 pos_tab_offset (w, start));
1060 if (bp.vpos >= height)
1062 if (point < bp.bufpos && !bp.contin)
1064 /* All changes are below the screen, and point is on the screen.
1065 We don't need to change the screen at all.
1066 But we need to update window_end_pos to account for
1067 any change in buffer size. */
1068 bp = *compute_motion (start, 0, lmargin,
1069 Z, height, 0,
1070 width, hscroll, pos_tab_offset (w, start));
1071 XFASTINT (w->window_end_vpos) = height;
1072 XFASTINT (w->window_end_pos) = Z - bp.bufpos;
1073 return 1;
1075 return 0;
1078 vpos = bp.vpos;
1080 /* Find beginning of that screen line. Must display from there. */
1081 bp = *vmotion (bp.bufpos, 0, width, hscroll, window);
1083 pos = bp.bufpos;
1084 val.hpos = lmargin;
1085 if (pos < start)
1086 return -1;
1088 /* If about to start displaying at the beginning of a continuation line,
1089 really start with previous screen line, in case it was not
1090 continued when last redisplayed */
1091 if ((bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0)
1093 /* Likewise if we have to worry about selective display. */
1094 (XTYPE (current_buffer->selective_display) == Lisp_Int
1095 && XINT (current_buffer->selective_display) > 0
1096 && bp.bufpos - 1 == beg_unchanged && vpos > 0))
1098 bp = *vmotion (bp.bufpos, -1, width, hscroll, window);
1099 --vpos;
1100 pos = bp.bufpos;
1103 if (bp.contin && bp.hpos != lmargin)
1105 val.hpos = bp.prevhpos - width + lmargin;
1106 pos--;
1109 bp.vpos = vpos;
1111 /* Find first visible newline after which no more is changed. */
1112 tem = find_next_newline (Z - max (end_unchanged, Z - ZV), 1);
1113 if (XTYPE (current_buffer->selective_display) == Lisp_Int
1114 && XINT (current_buffer->selective_display) > 0)
1115 while (tem < ZV - 1
1116 && (position_indentation (tem)
1117 >= XINT (current_buffer->selective_display)))
1118 tem = find_next_newline (tem, 1);
1120 /* Compute the cursor position after that newline. */
1121 ep = *compute_motion (pos, vpos, val.hpos, tem,
1122 height, - (1 << (SHORTBITS - 1)),
1123 width, hscroll, pos_tab_offset (w, bp.bufpos));
1125 /* If changes reach past the text available on the screen,
1126 just display rest of screen. */
1127 if (ep.bufpos > Z - XFASTINT (w->window_end_pos))
1128 stop_vpos = height;
1129 else
1130 stop_vpos = ep.vpos;
1132 /* If no newline before ep, the line ep is on includes some changes
1133 that must be displayed. Make sure we don't stop before it. */
1134 /* Also, if changes reach all the way until ep.bufpos,
1135 it is possible that something was deleted after the
1136 newline before it, so the following line must be redrawn. */
1137 if (stop_vpos == ep.vpos
1138 && (ep.bufpos == BEGV
1139 || FETCH_CHAR (ep.bufpos - 1) != '\n'
1140 || ep.bufpos == Z - end_unchanged))
1141 stop_vpos = ep.vpos + 1;
1143 cursor_vpos = -1;
1144 overlay_arrow_seen = 0;
1146 /* If changes do not reach to bottom of window,
1147 figure out how much to scroll the rest of the window */
1148 if (stop_vpos < height)
1150 /* Now determine how far up or down the rest of the window has moved */
1151 epto = pos_tab_offset (w, ep.bufpos);
1152 xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
1153 Z - XFASTINT (w->window_end_pos),
1154 10000, 0, width, hscroll, epto);
1155 scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
1157 /* Is everything on screen below the changes whitespace?
1158 If so, no scrolling is really necessary. */
1159 for (i = ep.bufpos; i < xp.bufpos; i++)
1161 tem = FETCH_CHAR (i);
1162 if (tem != ' ' && tem != '\n' && tem != '\t')
1163 break;
1165 if (i == xp.bufpos)
1166 return -2;
1168 XFASTINT (w->window_end_vpos) += scroll_amount;
1170 /* Before doing any scrolling, verify that point will be on screen. */
1171 if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height))
1173 if (point <= xp.bufpos)
1175 pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
1176 point, height, - (1 << (SHORTBITS - 1)),
1177 width, hscroll, epto);
1179 else
1181 pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
1182 point, height, - (1 << (SHORTBITS - 1)),
1183 width, hscroll, pos_tab_offset (w, xp.bufpos));
1185 if (pp.bufpos < point || pp.vpos == height)
1186 return 0;
1187 cursor_vpos = pp.vpos + top;
1188 cursor_hpos = pp.hpos + XFASTINT (w->left);
1191 if (stop_vpos - scroll_amount >= height
1192 || ep.bufpos == xp.bufpos)
1194 if (scroll_amount < 0)
1195 stop_vpos -= scroll_amount;
1196 scroll_amount = 0;
1197 /* In this path, we have altered window_end_vpos
1198 and not left it negative.
1199 We must make sure that, in case display is preempted
1200 before the screen changes to reflect what we do here,
1201 further updates will not come to try_window_id
1202 and assume the screen and window_end_vpos match. */
1203 blank_end_of_window = 1;
1205 else if (!scroll_amount)
1207 else if (bp.bufpos == Z - end_unchanged)
1209 /* If reprinting everything is nearly as fast as scrolling,
1210 don't bother scrolling. Can happen if lines are short. */
1211 if (scroll_cost (s, bp.vpos + top - scroll_amount,
1212 top + height - max (0, scroll_amount),
1213 scroll_amount)
1214 > xp.bufpos - bp.bufpos - 20)
1215 /* Return "try normal display with same window-start."
1216 Too bad we can't prevent further scroll-thinking. */
1217 return -2;
1218 /* If pure deletion, scroll up as many lines as possible.
1219 In common case of killing a line, this can save the
1220 following line from being overwritten by scrolling
1221 and therefore having to be redrawn. */
1222 tem = scroll_screen_lines (s, bp.vpos + top - scroll_amount,
1223 top + height - max (0, scroll_amount),
1224 scroll_amount);
1225 if (!tem) stop_vpos = height;
1227 else if (scroll_amount)
1229 /* If reprinting everything is nearly as fast as scrolling,
1230 don't bother scrolling. Can happen if lines are short. */
1231 /* Note that if scroll_amount > 0, xp.bufpos - bp.bufpos is an
1232 overestimate of cost of reprinting, since xp.bufpos
1233 would end up below the bottom of the window. */
1234 if (scroll_cost (s, ep.vpos + top - scroll_amount,
1235 top + height - max (0, scroll_amount),
1236 scroll_amount)
1237 > xp.bufpos - ep.bufpos - 20)
1238 /* Return "try normal display with same window-start."
1239 Too bad we can't prevent further scroll-thinking. */
1240 return -2;
1241 tem = scroll_screen_lines (s, ep.vpos + top - scroll_amount,
1242 top + height - max (0, scroll_amount),
1243 scroll_amount);
1244 if (!tem) stop_vpos = height;
1248 /* In any case, do not display past bottom of window */
1249 if (stop_vpos >= height)
1251 stop_vpos = height;
1252 scroll_amount = 0;
1255 /* Handle case where pos is before w->start --
1256 can happen if part of line had been clipped and is not clipped now */
1257 if (vpos == 0 && pos < marker_position (w->start))
1258 Fset_marker (w->start, make_number (pos), Qnil);
1260 /* Redisplay the lines where the text was changed */
1261 last_text_vpos = vpos;
1262 tab_offset = pos_tab_offset (w, pos);
1263 /* If we are starting display in mid-character, correct tab_offset
1264 to account for passing the line that that character really starts in. */
1265 if (val.hpos < lmargin)
1266 tab_offset += width;
1267 while (vpos < stop_vpos)
1269 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
1270 tab_offset += width;
1271 if (val.vpos) tab_offset = 0;
1272 if (pos != val.bufpos)
1273 last_text_vpos
1274 /* Next line, unless prev line ended in end of buffer with no cr */
1275 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
1276 pos = val.bufpos;
1279 /* There are two cases:
1280 1) we have displayed down to the bottom of the window
1281 2) we have scrolled lines below stop_vpos by scroll_amount */
1283 if (vpos == height)
1285 /* If last line is continued in middle of character,
1286 include the split character in the text considered on the screen */
1287 if (val.hpos < lmargin)
1288 val.bufpos++;
1289 XFASTINT (w->window_end_vpos) = last_text_vpos;
1290 XFASTINT (w->window_end_pos) = Z - val.bufpos;
1293 /* If scrolling made blank lines at window bottom,
1294 redisplay to fill those lines */
1295 if (scroll_amount < 0)
1297 /* Don't consider these lines for general-purpose scrolling.
1298 That will save time in the scrolling computation. */
1299 SCREEN_SCROLL_BOTTOM_VPOS (s) = xp.vpos;
1300 vpos = xp.vpos;
1301 pos = xp.bufpos;
1302 val.hpos = lmargin;
1303 if (pos == ZV)
1304 vpos = height + scroll_amount;
1305 else if (xp.contin && xp.hpos != lmargin)
1307 val.hpos = xp.prevhpos - width + lmargin;
1308 pos--;
1311 blank_end_of_window = 1;
1312 tab_offset = pos_tab_offset (w, pos);
1313 /* If we are starting display in mid-character, correct tab_offset
1314 to account for passing the line that that character starts in. */
1315 if (val.hpos < lmargin)
1316 tab_offset += width;
1318 while (vpos < height)
1320 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
1321 tab_offset += width;
1322 if (val.vpos) tab_offset = 0;
1323 pos = val.bufpos;
1326 /* Here is a case where display_text_line sets cursor_vpos wrong.
1327 Make it be fixed up, below. */
1328 if (xp.bufpos == ZV
1329 && xp.bufpos == point)
1330 cursor_vpos = -1;
1333 /* If bottom just moved off end of screen, change mode line percentage. */
1334 if (XFASTINT (w->window_end_pos) == 0
1335 && Z != val.bufpos)
1336 w->update_mode_line = Qt;
1338 /* Attempt to adjust end-of-text positions to new bottom line */
1339 if (scroll_amount)
1341 delta = height - xp.vpos;
1342 if (delta < 0
1343 || (delta > 0 && xp.bufpos <= ZV)
1344 || (delta == 0 && xp.hpos))
1346 val = *vmotion (Z - XFASTINT (w->window_end_pos),
1347 delta, width, hscroll, window);
1348 XFASTINT (w->window_end_pos) = Z - val.bufpos;
1349 XFASTINT (w->window_end_vpos) += val.vpos;
1353 w->window_end_valid = Qnil;
1355 /* If point was not in a line that was displayed, find it */
1356 if (cursor_vpos < 0)
1358 val = *compute_motion (start, 0, lmargin, point, 10000, 10000,
1359 width, hscroll, pos_tab_offset (w, start));
1360 /* Admit failure if point is off screen now */
1361 if (val.vpos >= height)
1363 for (vpos = 0; vpos < height; vpos++)
1364 cancel_line (vpos + top, s);
1365 return 0;
1367 cursor_vpos = val.vpos + top;
1368 cursor_hpos = val.hpos + XFASTINT (w->left);
1371 SCREEN_CURSOR_X (s) = max (0, cursor_hpos);
1372 SCREEN_CURSOR_Y (s) = cursor_vpos;
1374 if (debug_end_pos)
1376 val = *compute_motion (start, 0, lmargin, ZV,
1377 height, - (1 << (SHORTBITS - 1)),
1378 width, hscroll, pos_tab_offset (w, start));
1379 if (val.vpos != XFASTINT (w->window_end_vpos))
1380 abort ();
1381 if (XFASTINT (w->window_end_pos)
1382 != Z - val.bufpos)
1383 abort ();
1386 return 1;
1389 /* Copy glyphs from the rope FROM to T.
1390 But don't actually copy the parts that would come in before S.
1391 Value is T, advanced past the copied data.
1393 Characters in FROM are grouped into units of `sizeof GLYPH' chars;
1394 any extra chars at the end of FROM are ignored. */
1396 GLYPH *
1397 copy_rope (t, s, from)
1398 register GLYPH *t; /* Copy to here. */
1399 register GLYPH *s; /* Starting point. */
1400 Lisp_Object from; /* Data to copy; known to be a string. */
1402 register int n = XSTRING (from)->size / sizeof (GLYPH);
1403 register GLYPH *f = (GLYPH *) XSTRING (from)->data;
1405 while (n--)
1407 if (t >= s) *t = *f;
1408 ++t;
1409 ++f;
1411 return t;
1414 /* Display one line of window w, starting at position START in W's buffer.
1415 Display starting at horizontal position HPOS, which is normally zero
1416 or negative. A negative value causes output up to hpos = 0 to be discarded.
1417 This is done for negative hscroll, or when this is a continuation line
1418 and the continuation occurred in the middle of a multi-column character.
1420 TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
1422 Display on position VPOS on the screen. (origin 0).
1424 Returns a STRUCT POSITION giving character to start next line with
1425 and where to display it, including a zero or negative hpos.
1426 The vpos field is not really a vpos; it is 1 unless the line is continued */
1428 struct position val_display_text_line;
1430 static struct position *
1431 display_text_line (w, start, vpos, hpos, taboffset)
1432 struct window *w;
1433 int start;
1434 int vpos;
1435 int hpos;
1436 int taboffset;
1438 register int pos = start;
1439 register int c;
1440 register GLYPH *p1;
1441 int end;
1442 register int pause;
1443 register unsigned char *p;
1444 GLYPH *endp;
1445 register GLYPH *startp;
1446 register GLYPH *p1prev;
1447 SCREEN_PTR s = XSCREEN (w->screen);
1448 int tab_width = XINT (current_buffer->tab_width);
1449 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
1450 int width = XFASTINT (w->width) - 1
1451 - (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s));
1452 struct position val;
1453 int lastpos;
1454 int invis;
1455 int hscroll = XINT (w->hscroll);
1456 int truncate = hscroll
1457 || (truncate_partial_width_windows
1458 && XFASTINT (w->width) < SCREEN_WIDTH (s))
1459 || !NILP (current_buffer->truncate_lines);
1460 int selective
1461 = XTYPE (current_buffer->selective_display) == Lisp_Int
1462 ? XINT (current_buffer->selective_display)
1463 : !NILP (current_buffer->selective_display) ? -1 : 0;
1464 #ifndef old
1465 int selective_e = selective && !NILP (current_buffer->selective_display_ellipses);
1466 #endif
1467 register struct screen_glyphs *desired_glyphs = SCREEN_DESIRED_GLYPHS (s);
1468 register struct Lisp_Vector *dp = window_display_table (w);
1469 int selective_rlen
1470 = (selective && dp && XTYPE (DISP_INVIS_ROPE (dp)) == Lisp_String
1471 ? XSTRING (DISP_INVIS_ROPE (dp))->size / sizeof (GLYPH) : 0);
1472 GLYPH truncator = (dp == 0 || XTYPE (DISP_TRUNC_GLYPH (dp)) != Lisp_Int
1473 ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
1474 GLYPH continuer = (dp == 0 || XTYPE (DISP_CONTINUE_GLYPH (dp)) != Lisp_Int
1475 ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
1477 hpos += XFASTINT (w->left);
1478 get_display_line (s, vpos, XFASTINT (w->left));
1479 if (tab_width <= 0 || tab_width > 20) tab_width = 8;
1481 if (MINI_WINDOW_P (w) && start == 1
1482 && vpos == XFASTINT (w->top))
1484 if (minibuf_prompt)
1485 hpos = display_string (w, vpos, minibuf_prompt, hpos,
1486 (!truncate ? continuer : truncator),
1487 -1, -1);
1488 minibuf_prompt_width = hpos;
1491 desired_glyphs->bufp[vpos] = pos;
1492 p1 = desired_glyphs->glyphs[vpos] + hpos;
1493 end = ZV;
1494 startp = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
1495 endp = startp + width;
1497 /* Loop generating characters.
1498 Stop at end of buffer, before newline,
1499 or if reach or pass continuation column. */
1501 pause = pos;
1502 while (p1 < endp)
1504 p1prev = p1;
1505 if (pos == pause)
1507 if (pos == end)
1508 break;
1509 if (pos == point && cursor_vpos < 0)
1511 cursor_vpos = vpos;
1512 cursor_hpos = p1 - startp;
1515 pause = end;
1516 if (pos < point && point < pause)
1517 pause = point;
1518 if (pos < GPT && GPT < pause)
1519 pause = GPT;
1521 p = &FETCH_CHAR (pos);
1523 c = *p++;
1524 if (c >= 040 && c < 0177
1525 && (dp == 0 || XTYPE (DISP_CHAR_ROPE (dp, c)) != Lisp_String))
1527 if (p1 >= startp)
1528 *p1 = c;
1529 p1++;
1531 else if (c == '\n')
1533 invis = 0;
1534 while (pos < end
1535 && selective > 0
1536 && position_indentation (pos + 1) >= selective)
1538 invis = 1;
1539 pos = find_next_newline (pos + 1, 1);
1540 if (FETCH_CHAR (pos - 1) == '\n')
1541 pos--;
1543 if (invis && selective_rlen > 0 && p1 >= startp)
1545 p1 += selective_rlen;
1546 if (p1 - startp > width)
1547 p1 = endp;
1548 bcopy (XSTRING (DISP_INVIS_ROPE (dp))->data, p1prev,
1549 (p1 - p1prev) * sizeof (GLYPH));
1551 break;
1553 else if (c == '\t')
1557 if (p1 >= startp && p1 < endp)
1558 *p1 = SPACEGLYPH;
1559 p1++;
1561 while ((p1 - startp + taboffset + hscroll - (hscroll > 0))
1562 % tab_width);
1564 else if (c == Ctl ('M') && selective == -1)
1566 pos = find_next_newline (pos, 1);
1567 if (FETCH_CHAR (pos - 1) == '\n')
1568 pos--;
1569 if (selective_rlen > 0)
1571 p1 += selective_rlen;
1572 if (p1 - startp > width)
1573 p1 = endp;
1574 bcopy (XSTRING (DISP_INVIS_ROPE (dp))->data, p1prev,
1575 (p1 - p1prev) * sizeof (GLYPH));
1577 break;
1579 else if (dp != 0 && XTYPE (DISP_CHAR_ROPE (dp, c)) == Lisp_String)
1581 p1 = copy_rope (p1, startp, DISP_CHAR_ROPE (dp, c));
1583 else if (c < 0200 && ctl_arrow)
1585 if (p1 >= startp)
1586 *p1 = (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
1587 ? XINT (DISP_CTRL_GLYPH (dp)) : '^');
1588 p1++;
1589 if (p1 >= startp && p1 < endp)
1590 *p1 = c ^ 0100;
1591 p1++;
1593 else
1595 if (p1 >= startp)
1596 *p1 = (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
1597 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\');
1598 p1++;
1599 if (p1 >= startp && p1 < endp)
1600 *p1 = (c >> 6) + '0';
1601 p1++;
1602 if (p1 >= startp && p1 < endp)
1603 *p1 = (7 & (c >> 3)) + '0';
1604 p1++;
1605 if (p1 >= startp && p1 < endp)
1606 *p1 = (7 & c) + '0';
1607 p1++;
1609 pos++;
1612 val.hpos = - XINT (w->hscroll);
1613 if (val.hpos)
1614 val.hpos++;
1616 val.vpos = 1;
1618 lastpos = pos;
1620 /* Handle continuation in middle of a character */
1621 /* by backing up over it */
1622 if (p1 > endp)
1624 /* Start the next line with that same character */
1625 pos--;
1626 /* but at a negative hpos, to skip the columns output on this line. */
1627 val.hpos += p1prev - endp;
1628 /* Keep in this line everything up to the continuation column. */
1629 p1 = endp;
1632 /* Finish deciding which character to start the next line on,
1633 and what hpos to start it at.
1634 Also set `lastpos' to the last position which counts as "on this line"
1635 for cursor-positioning. */
1637 if (pos < ZV)
1639 if (FETCH_CHAR (pos) == '\n')
1640 /* If stopped due to a newline, start next line after it */
1641 pos++;
1642 else
1643 /* Stopped due to right margin of window */
1645 if (truncate)
1647 *p1++ = truncator;
1648 /* Truncating => start next line after next newline,
1649 and point is on this line if it is before the newline,
1650 and skip none of first char of next line */
1651 pos = find_next_newline (pos, 1);
1652 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
1654 lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
1656 else
1658 *p1++ = continuer;
1659 val.vpos = 0;
1660 lastpos--;
1665 /* If point is at eol or in invisible text at eol,
1666 record its screen location now. */
1668 if (start <= point && point <= lastpos && cursor_vpos < 0)
1670 cursor_vpos = vpos;
1671 cursor_hpos = p1 - startp;
1674 if (cursor_vpos == vpos)
1676 if (cursor_hpos < 0) cursor_hpos = 0;
1677 if (cursor_hpos > width) cursor_hpos = width;
1678 cursor_hpos += XFASTINT (w->left);
1679 if (w == XWINDOW (SCREEN_SELECTED_WINDOW (s)))
1681 SCREEN_CURSOR_Y (s) = cursor_vpos;
1682 SCREEN_CURSOR_X (s) = cursor_hpos;
1684 if (w == XWINDOW (selected_window))
1686 /* Line is not continued and did not start
1687 in middle of character */
1688 if ((hpos - XFASTINT (w->left)
1689 == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
1690 && val.vpos)
1692 this_line_bufpos = start;
1693 this_line_buffer = current_buffer;
1694 this_line_vpos = cursor_vpos;
1695 this_line_start_hpos = hpos;
1696 this_line_endpos = Z - lastpos;
1698 else
1699 this_line_bufpos = 0;
1704 /* If hscroll and line not empty, insert truncation-at-left marker */
1705 if (hscroll && lastpos != start)
1707 *startp = truncator;
1708 if (p1 <= startp)
1709 p1 = startp + 1;
1712 if (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s))
1714 endp++;
1715 if (p1 < startp) p1 = startp;
1716 while (p1 < endp) *p1++ = SPACEGLYPH;
1717 *p1++ = '|';
1719 desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
1720 p1 - desired_glyphs->glyphs[vpos]);
1721 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
1723 /* If the start of this line is the overlay arrow-position,
1724 then put the arrow string into the display-line. */
1726 if (XTYPE (Voverlay_arrow_position) == Lisp_Marker
1727 && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
1728 && start == marker_position (Voverlay_arrow_position)
1729 && XTYPE (Voverlay_arrow_string) == Lisp_String
1730 && ! overlay_arrow_seen)
1732 unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
1733 int i;
1734 int len = XSTRING (Voverlay_arrow_string)->size;
1736 if (len > XFASTINT (w->width) - 1)
1737 len = XFASTINT (w->width) - 1;
1738 for (i = 0; i < len; i++)
1739 startp[i] = p[i];
1740 if (desired_glyphs->used[vpos] <
1741 (len + startp - desired_glyphs->glyphs[vpos]))
1742 desired_glyphs->used[vpos] = len + startp - desired_glyphs->glyphs[vpos];
1744 overlay_arrow_seen = 1;
1747 val.bufpos = pos;
1748 val_display_text_line = val;
1749 return &val_display_text_line;
1752 /* Display the mode line for window w */
1754 static void
1755 display_mode_line (w)
1756 struct window *w;
1758 register int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
1759 register int left = XFASTINT (w->left);
1760 register int right = XFASTINT (w->width) + left;
1761 register SCREEN_PTR s = XSCREEN (WINDOW_SCREEN (w));
1763 get_display_line (s, vpos, left);
1764 display_mode_element (w, vpos, left, 0, right, right,
1765 current_buffer->mode_line_format);
1766 SCREEN_DESIRED_GLYPHS (s)->bufp[vpos] = 0;
1768 /* Make the mode line inverse video if the entire line
1769 is made of mode lines.
1770 I.e. if this window is full width,
1771 or if it is the child of a full width window
1772 (which implies that that window is split side-by-side
1773 and the rest of this line is mode lines of the sibling windows). */
1774 if (XFASTINT (w->width) == SCREEN_WIDTH (s)
1775 || XFASTINT (XWINDOW (w->parent)->width) == SCREEN_WIDTH (s))
1776 s->desired_glyphs->highlight[vpos] = mode_line_inverse_video;
1778 #ifdef HAVE_X_WINDOWS
1779 /* I'm trying this out because I saw Unimpress use it, but it's
1780 possible that this may mess adversely with some window managers. jla */
1782 if (SCREEN_IS_X (s)
1783 && ! SCREEN_MINIBUF_ONLY_P (s)
1784 && w == XWINDOW (s->selected_window)
1785 && (NILP (Fstring_equal (XBUFFER (w->buffer)->name, s->name))))
1786 x_set_name (s, XBUFFER (w->buffer)->name, Qnil);
1787 #endif
1790 /* Contribute ELT to the mode line for window W.
1791 How it translates into text depends on its data type.
1793 VPOS is the position of the mode line being displayed.
1795 HPOS is the position (absolute on screen) where this element's text
1796 should start. The output is truncated automatically at the right
1797 edge of window W.
1799 DEPTH is the depth in recursion. It is used to prevent
1800 infinite recursion here.
1802 MINENDCOL is the hpos before which the element may not end.
1803 The element is padded at the right with spaces if nec
1804 to reach this column.
1806 MAXENDCOL is the hpos past which this element may not extend.
1807 If MINENDCOL is > MAXENDCOL, MINENDCOL takes priority.
1808 (This is necessary to make nested padding and truncation work.)
1810 Returns the hpos of the end of the text generated by ELT.
1811 The next element will receive that value as its HPOS arg,
1812 so as to concatenate the elements. */
1814 static int
1815 display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
1816 struct window *w;
1817 register int vpos, hpos;
1818 int depth;
1819 int minendcol;
1820 register int maxendcol;
1821 register Lisp_Object elt;
1823 tail_recurse:
1824 if (depth > 10)
1825 goto invalid;
1827 depth++;
1829 #ifdef SWITCH_ENUM_BUG
1830 switch ((int) XTYPE (elt))
1831 #else
1832 switch (XTYPE (elt))
1833 #endif
1835 case Lisp_String:
1837 /* A string: output it and check for %-constructs within it. */
1838 register unsigned char c;
1839 register unsigned char *this = XSTRING (elt)->data;
1841 while (hpos < maxendcol && *this)
1843 unsigned char *last = this;
1844 while ((c = *this++) != '\0' && c != '%')
1846 if (this - 1 != last)
1848 register int lim = --this - last + hpos;
1849 hpos = display_string (w, vpos, last, hpos, 0, hpos,
1850 min (lim, maxendcol));
1852 else /* c == '%' */
1854 register int spec_width = 0;
1856 /* We can't allow -ve args due to the "%-" construct */
1857 /* Argument specifies minwidth but not maxwidth
1858 (maxwidth can be specified by
1859 (<negative-number> . <stuff>) mode-line elements) */
1861 while ((c = *this++) >= '0' && c <= '9')
1863 spec_width = spec_width * 10 + (c - '0');
1866 spec_width += hpos;
1867 if (spec_width > maxendcol)
1868 spec_width = maxendcol;
1870 if (c == 'M')
1871 hpos = display_mode_element (w, vpos, hpos, depth,
1872 spec_width, maxendcol,
1873 Vglobal_mode_string);
1874 else if (c != 0)
1875 hpos = display_string (w, vpos,
1876 decode_mode_spec (w, c,
1877 maxendcol - hpos),
1878 hpos, 0, spec_width, maxendcol);
1882 break;
1884 case Lisp_Symbol:
1885 /* A symbol: process the value of the symbol recursively
1886 as if it appeared here directly. Avoid error if symbol void.
1887 Special case: if value of symbol is a string, output the string
1888 literally. */
1890 register Lisp_Object tem;
1891 tem = Fboundp (elt);
1892 if (!NILP (tem))
1894 tem = Fsymbol_value (elt);
1895 /* If value is a string, output that string literally:
1896 don't check for % within it. */
1897 if (XTYPE (tem) == Lisp_String)
1898 hpos = display_string (w, vpos, XSTRING (tem)->data,
1899 hpos, 0, minendcol, maxendcol);
1900 /* Give up right away for nil or t. */
1901 else if (!EQ (tem, elt))
1902 { elt = tem; goto tail_recurse; }
1905 break;
1907 case Lisp_Cons:
1909 register Lisp_Object car, tem;
1911 /* A cons cell: three distinct cases.
1912 If first element is a string or a cons, process all the elements
1913 and effectively concatenate them.
1914 If first element is a negative number, truncate displaying cdr to
1915 at most that many characters. If positive, pad (with spaces)
1916 to at least that many characters.
1917 If first element is a symbol, process the cadr or caddr recursively
1918 according to whether the symbol's value is non-nil or nil. */
1919 car = XCONS (elt)->car;
1920 if (XTYPE (car) == Lisp_Symbol)
1922 tem = Fboundp (car);
1923 elt = XCONS (elt)->cdr;
1924 if (XTYPE (elt) != Lisp_Cons)
1925 goto invalid;
1926 /* elt is now the cdr, and we know it is a cons cell.
1927 Use its car if CAR has a non-nil value. */
1928 if (!NILP (tem))
1930 tem = Fsymbol_value (car);
1931 if (!NILP (tem))
1932 { elt = XCONS (elt)->car; goto tail_recurse; }
1934 /* Symbol's value is nil (or symbol is unbound)
1935 Get the cddr of the original list
1936 and if possible find the caddr and use that. */
1937 elt = XCONS (elt)->cdr;
1938 if (NILP (elt))
1939 break;
1940 else if (XTYPE (elt) != Lisp_Cons)
1941 goto invalid;
1942 elt = XCONS (elt)->car;
1943 goto tail_recurse;
1945 else if (XTYPE (car) == Lisp_Int)
1947 register int lim = XINT (car);
1948 elt = XCONS (elt)->cdr;
1949 if (lim < 0)
1950 /* Negative int means reduce maximum width.
1951 DO NOT change MINENDCOL here!
1952 (20 -10 . foo) should truncate foo to 10 col
1953 and then pad to 20. */
1954 maxendcol = min (maxendcol, hpos - lim);
1955 else if (lim > 0)
1957 /* Padding specified. Don't let it be more than
1958 current maximum. */
1959 lim += hpos;
1960 if (lim > maxendcol)
1961 lim = maxendcol;
1962 /* If that's more padding than already wanted, queue it.
1963 But don't reduce padding already specified even if
1964 that is beyond the current truncation point. */
1965 if (lim > minendcol)
1966 minendcol = lim;
1968 goto tail_recurse;
1970 else if (XTYPE (car) == Lisp_String || XTYPE (car) == Lisp_Cons)
1972 register int limit = 50;
1973 /* LIMIT is to protect against circular lists. */
1974 while (XTYPE (elt) == Lisp_Cons && --limit > 0
1975 && hpos < maxendcol)
1977 hpos = display_mode_element (w, vpos, hpos, depth,
1978 hpos, maxendcol,
1979 XCONS (elt)->car);
1980 elt = XCONS (elt)->cdr;
1984 break;
1986 default:
1987 invalid:
1988 return (display_string (w, vpos, "*invalid*", hpos, 0,
1989 minendcol, maxendcol));
1992 end:
1993 if (minendcol > hpos)
1994 hpos = display_string (w, vpos, "", hpos, 0, minendcol, -1);
1995 return hpos;
1998 /* Return a string for the output of a mode line %-spec for window W,
1999 generated by character C and width MAXWIDTH. */
2001 static char *
2002 decode_mode_spec (w, c, maxwidth)
2003 struct window *w;
2004 register char c;
2005 register int maxwidth;
2007 Lisp_Object obj = Qnil;
2008 SCREEN_PTR scr = XSCREEN (WINDOW_SCREEN (w));
2009 char *decode_mode_spec_buf = (char *) SCREEN_TEMP_GLYPHS (scr)->total_contents;
2011 if (maxwidth > SCREEN_WIDTH (scr))
2012 maxwidth = SCREEN_WIDTH (scr);
2014 switch (c)
2016 case 'b':
2017 obj = current_buffer->name;
2018 #if 0
2019 if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
2021 bcopy (XSTRING (obj)->data, decode_mode_spec_buf, maxwidth - 1);
2022 decode_mode_spec_buf[maxwidth - 1] = '\\';
2023 decode_mode_spec_buf[maxwidth] = '\0';
2024 return decode_mode_spec_buf;
2026 #endif
2027 break;
2029 case 'f':
2030 obj = current_buffer->filename;
2031 #if 0
2032 if (NILP (obj))
2033 return "[none]";
2034 else if (XTYPE (obj) == Lisp_String && XSTRING (obj)->size > maxwidth)
2036 bcopy ("...", decode_mode_spec_buf, 3);
2037 bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
2038 decode_mode_spec_buf + 3, maxwidth - 3);
2039 return decode_mode_spec_buf;
2041 #endif
2042 break;
2044 case 'm':
2045 obj = current_buffer->mode_name;
2046 break;
2048 case 'n':
2049 if (BEGV > BEG || ZV < Z)
2050 return " Narrow";
2051 break;
2053 case '*':
2054 if (!NILP (current_buffer->read_only))
2055 return "%";
2056 if (MODIFF > current_buffer->save_modified)
2057 return "*";
2058 return "-";
2060 case 's':
2061 /* status of process */
2062 #ifdef subprocesses
2063 obj = Fget_buffer_process (Fcurrent_buffer ());
2064 if (NILP (obj))
2065 return "no process";
2066 obj = Fsymbol_name (Fprocess_status (obj));
2067 break;
2068 #else
2069 return "no processes";
2070 #endif /* subprocesses */
2072 case 'p':
2074 int pos = marker_position (w->start);
2075 int total = ZV - BEGV;
2077 if (XFASTINT (w->window_end_pos) <= Z - ZV)
2079 if (pos <= BEGV)
2080 return "All";
2081 else
2082 return "Bottom";
2084 else if (pos <= BEGV)
2085 return "Top";
2086 else
2088 total = ((pos - BEGV) * 100 + total - 1) / total;
2089 /* We can't normally display a 3-digit number,
2090 so get us a 2-digit number that is close. */
2091 if (total == 100)
2092 total = 99;
2093 sprintf (decode_mode_spec_buf, "%2d%%", total);
2094 return decode_mode_spec_buf;
2098 case '%':
2099 return "%";
2101 case '[':
2103 int i;
2104 char *p;
2106 if (command_loop_level > 5)
2107 return "[[[... ";
2108 p = decode_mode_spec_buf;
2109 for (i = 0; i < command_loop_level; i++)
2110 *p++ = '[';
2111 *p = 0;
2112 return decode_mode_spec_buf;
2115 case ']':
2117 int i;
2118 char *p;
2120 if (command_loop_level > 5)
2121 return " ...]]]";
2122 p = decode_mode_spec_buf;
2123 for (i = 0; i < command_loop_level; i++)
2124 *p++ = ']';
2125 *p = 0;
2126 return decode_mode_spec_buf;
2129 case '-':
2131 static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
2132 register char *p;
2133 register int i;
2135 if (maxwidth < sizeof (lots_of_dashes))
2136 return lots_of_dashes;
2137 else
2139 for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
2140 *p++ = '-';
2141 *p = '\0';
2143 return decode_mode_spec_buf;
2147 if (XTYPE (obj) == Lisp_String)
2148 return (char *) XSTRING (obj)->data;
2149 else
2150 return "";
2153 /* Display STRING on one line of window W, starting at HPOS.
2154 Display at position VPOS. Caller should have done get_display_line.
2156 TRUNCATE is GLYPH to display at end if truncated. Zero for none.
2158 MINCOL is the first column ok to end at. (Pad with spaces to this col.)
2159 MAXCOL is the last column ok to end at. Truncate here.
2160 -1 for MINCOL or MAXCOL means no explicit minimum or maximum.
2161 Both count from the left edge of the screen, as does HPOS.
2162 The right edge of W is an implicit maximum.
2163 If TRUNCATE is nonzero, the implicit maximum is one column before the edge.
2165 Returns ending hpos */
2167 static int
2168 display_string (w, vpos, string, hpos, truncate, mincol, maxcol)
2169 struct window *w;
2170 unsigned char *string;
2171 int vpos, hpos;
2172 GLYPH truncate;
2173 int mincol, maxcol;
2175 register int c;
2176 register GLYPH *p1;
2177 int hscroll = XINT (w->hscroll);
2178 int tab_width = XINT (current_buffer->tab_width);
2179 register GLYPH *start;
2180 register GLYPH *end;
2181 struct screen_glyphs *desired_glyphs = SCREEN_DESIRED_GLYPHS (XSCREEN (w->screen));
2182 GLYPH *p1start = desired_glyphs->glyphs[vpos] + hpos;
2183 int window_width = XFASTINT (w->width);
2185 /* Use the standard display table, not the window's display table.
2186 We don't want the mode line in rot13. */
2187 register struct Lisp_Vector *dp = 0;
2189 if (XTYPE (Vstandard_display_table) == Lisp_Vector
2190 && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
2191 dp = XVECTOR (Vstandard_display_table);
2193 if (tab_width <= 0 || tab_width > 20) tab_width = 8;
2195 p1 = p1start;
2196 start = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
2197 end = start + window_width - (truncate != 0);
2199 if ((window_width + XFASTINT (w->left))
2200 != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w))))
2201 *end-- = '|';
2203 if (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol)
2204 end = desired_glyphs->glyphs[vpos] + maxcol;
2205 if (maxcol >= 0 && mincol > maxcol)
2206 mincol = maxcol;
2208 while (p1 < end)
2210 c = *string++;
2211 if (!c) break;
2212 if (c >= 040 && c < 0177
2213 && (dp == 0 || XTYPE (DISP_CHAR_ROPE (dp, c)) != Lisp_String))
2215 if (p1 >= start)
2216 *p1 = c;
2217 p1++;
2219 else if (c == '\t')
2223 if (p1 >= start && p1 < end)
2224 *p1 = SPACEGLYPH;
2225 p1++;
2227 while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
2229 else if (dp != 0 && XTYPE (DISP_CHAR_ROPE (dp, c)) == Lisp_String)
2230 p1 = copy_rope (p1, start, DISP_CHAR_ROPE (dp, c));
2231 else if (c < 0200 && buffer_defaults.ctl_arrow)
2233 if (p1 >= start)
2234 *p1 = (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
2235 ? XINT (DISP_CTRL_GLYPH (dp)) : '^');
2236 p1++;
2237 if (p1 >= start && p1 < end)
2238 *p1 = c ^ 0100;
2239 p1++;
2241 else
2243 if (p1 >= start)
2244 *p1 = (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
2245 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\');
2246 p1++;
2247 if (p1 >= start && p1 < end)
2248 *p1 = (c >> 6) + '0';
2249 p1++;
2250 if (p1 >= start && p1 < end)
2251 *p1 = (7 & (c >> 3)) + '0';
2252 p1++;
2253 if (p1 >= start && p1 < end)
2254 *p1 = (7 & c) + '0';
2255 p1++;
2259 if (c)
2261 p1 = end;
2262 if (truncate) *p1++ = truncate;
2264 else if (mincol >= 0)
2266 end = desired_glyphs->glyphs[vpos] + mincol;
2267 while (p1 < end)
2268 *p1++ = SPACEGLYPH;
2272 register int len = p1 - desired_glyphs->glyphs[vpos];
2274 if (len > desired_glyphs->used[vpos])
2275 desired_glyphs->used[vpos] = len;
2276 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
2278 return len;
2282 void
2283 syms_of_xdisp ()
2285 staticpro (&last_arrow_position);
2286 staticpro (&last_arrow_string);
2287 last_arrow_position = Qnil;
2288 last_arrow_string = Qnil;
2290 DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
2291 "String displayed by mode-line-format's \"%m\" specifiation.");
2292 Vglobal_mode_string = Qnil;
2294 DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
2295 "Marker for where to display an arrow on top of the buffer text.\n\
2296 This must be the beginning of a line in order to work.\n\
2297 See also `overlay-arrow-string'.");
2298 Voverlay_arrow_position = Qnil;
2300 DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
2301 "String to display as an arrow. See also `overlay-arrow-position'.");
2302 Voverlay_arrow_string = Qnil;
2304 DEFVAR_INT ("scroll-step", &scroll_step,
2305 "*The number of lines to try scrolling a window by when point moves out.\n\
2306 If that fails to bring point back on screen, point is centered instead.\n\
2307 If this is zero, point is always centered after it moves off screen.");
2309 DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
2311 DEFVAR_BOOL ("truncate-partial-width-windows",
2312 &truncate_partial_width_windows,
2313 "*Non-nil means truncate lines in all windows less than full screen wide.");
2314 truncate_partial_width_windows = 1;
2316 DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
2317 "*Non-nil means use inverse video for the mode line.");
2318 mode_line_inverse_video = 1;
2320 #ifndef MULTI_SCREEN
2321 defsubr (&Sredraw_display);
2322 #endif /* MULTI_SCREEN */
2325 /* initialize the window system */
2326 init_xdisp ()
2328 Lisp_Object root_window;
2329 #ifndef COMPILER_REGISTER_BUG
2330 register
2331 #endif /* COMPILER_REGISTER_BUG */
2332 struct window *mini_w;
2334 this_line_bufpos = 0;
2336 mini_w = XWINDOW (minibuf_window);
2337 root_window = mini_w->prev;
2339 echo_area_glyphs = 0;
2340 previous_echo_glyphs = 0;
2342 if (!noninteractive)
2344 SCREEN_PTR s = XSCREEN (WINDOW_SCREEN (XWINDOW (root_window)));
2345 XFASTINT (XWINDOW (root_window)->top) = 0;
2346 set_window_height (root_window, SCREEN_HEIGHT (s) - 1, 0);
2347 XFASTINT (mini_w->top) = SCREEN_HEIGHT (s) - 1;
2348 set_window_height (minibuf_window, 1, 0);
2350 XFASTINT (XWINDOW (root_window)->width) = SCREEN_WIDTH (s);
2351 XFASTINT (mini_w->width) = SCREEN_WIDTH (s);