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)
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. */
23 /*#include <ctype.h>*/
29 #include "dispextern.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
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. */
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. */
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
;
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. */
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. */
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 */
165 /* Nonzero if window sizes or contents have changed
166 since last redisplay that finished */
167 int windows_or_buffers_changed
;
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 */
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 */
189 #endif /* not MULTI_SCREEN */
191 /* Buffer used for messages formatted by `message'. */
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 */
202 message (m
, a1
, a2
, a3
)
207 if (noninteractive_need_newline
)
209 noninteractive_need_newline
= 0;
210 fprintf (stderr
, m
, a1
, a2
, a3
);
211 fprintf (stderr
, "\n");
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
))
220 choose_minibuf_screen ();
221 Fmake_screen_visible (WINDOW_SCREEN (XWINDOW (minibuf_window
)));
230 doprnt (SCREEN_MESSAGE_BUF (selected_screen
),
231 SCREEN_WIDTH (selected_screen
), m
, 0, 3, a
);
233 doprnt (SCREEN_MESSAGE_BUF (selected_screen
),
234 SCREEN_WIDTH (selected_screen
), m
, 0, 3, &a1
);
235 #endif /* NO_ARG_ARRAY */
237 echo_area_glyphs
= SCREEN_MESSAGE_BUF (selected_screen
);
239 /* Print should start at the beginning of the message
241 message_buf_print
= 0;
243 do_pending_window_change ();
244 echo_area_display ();
245 update_screen (XSCREEN (XWINDOW (minibuf_window
)->screen
), 1, 1);
246 do_pending_window_change ();
250 /* Specify m, a string, as a message in the minibuf. */
257 if (noninteractive_need_newline
)
259 noninteractive_need_newline
= 0;
260 fprintf (stderr
, "%s\n", m
);
263 /* A null message buffer means that the screen hasn't really been
264 initialized yet. Error messages get reported properly by
265 cmd_error, so this must be just an informative message; toss it. */
266 else if (INTERACTIVE
&& SCREEN_MESSAGE_BUF (selected_screen
))
269 choose_minibuf_screen ();
270 Fmake_screen_visible (WINDOW_SCREEN (XWINDOW (minibuf_window
)));
273 echo_area_glyphs
= m
;
274 do_pending_window_change ();
275 echo_area_display ();
276 update_screen (XSCREEN (XWINDOW (minibuf_window
)->screen
), 1, 1);
277 do_pending_window_change ();
288 choose_minibuf_screen ();
289 s
= XSCREEN (WINDOW_SCREEN (XWINDOW (minibuf_window
)));
291 if (! SCREEN_VISIBLE_P (s
))
301 if (echo_area_glyphs
|| minibuf_level
== 0)
303 vpos
= XFASTINT (XWINDOW (minibuf_window
)->top
);
304 get_display_line (s
, vpos
, 0);
305 display_string (XWINDOW (minibuf_window
), vpos
,
306 echo_area_glyphs
? echo_area_glyphs
: "",
307 0, 0, 0, SCREEN_WIDTH (s
));
309 /* If desired cursor location is on this line, put it at end of text */
310 if (SCREEN_CURSOR_Y (s
) == vpos
)
311 SCREEN_CURSOR_X (s
) = s
->desired_glyphs
->used
[vpos
];
313 else if (!EQ (minibuf_window
, selected_window
))
314 windows_or_buffers_changed
++;
316 if (EQ (minibuf_window
, selected_window
))
317 this_line_bufpos
= 0;
319 previous_echo_glyphs
= echo_area_glyphs
;
322 /* Do a screen update, taking possible shortcuts into account.
323 This is the main external entry point for redisplay.
325 If the last redisplay displayed an echo area message and that
326 message is no longer requested, we clear the echo area
327 or bring back the minibuffer if that is in use.
329 Everyone would like to have a hook here to call eval,
330 but that cannot be done safely without a lot of changes elsewhere.
331 This can be called from signal handlers; with alarms set up;
332 or with synchronous processes running.
333 See the function `echo' in keyboard.c.
334 See Fcall_process; if you called it from here, it could be
335 entered recursively. */
340 register struct window
*w
= XWINDOW (selected_window
);
344 register int tlbufpos
, tlendpos
;
346 extern int input_pending
;
351 /* Notice any pending interrupt request to change screen size. */
352 do_pending_window_change ();
360 /* Normally the message* functions will have already displayed and
361 updated the echo area, but the screen may have been trashed, or
362 the update may have been preempted, so display the echo area
364 if (echo_area_glyphs
|| previous_echo_glyphs
)
366 echo_area_display ();
370 if (clip_changed
|| windows_or_buffers_changed
)
373 /* Detect case that we need to write a star in the mode line. */
374 if (XFASTINT (w
->last_modified
) < MODIFF
375 && XFASTINT (w
->last_modified
) <= current_buffer
->save_modified
)
377 w
->update_mode_line
= Qt
;
378 if (buffer_shared
> 1)
382 SCREEN_SCROLL_BOTTOM_VPOS (XSCREEN (w
->screen
)) = -1;
384 all_windows
= update_mode_lines
|| buffer_shared
> 1;
386 /* If specs for an arrow have changed, do thorough redisplay
387 to ensure we remove any arrow that should no longer exist. */
388 if (Voverlay_arrow_position
!= last_arrow_position
389 || Voverlay_arrow_string
!= last_arrow_string
)
390 all_windows
= 1, clip_changed
= 1;
392 tlbufpos
= this_line_bufpos
;
393 tlendpos
= this_line_endpos
;
394 if (!all_windows
&& tlbufpos
> 0 && NULL (w
->update_mode_line
)
395 && SCREEN_VISIBLE_P (XSCREEN (w
->screen
))
396 /* Make sure recorded data applies to current buffer, etc */
397 && this_line_buffer
== current_buffer
398 && current_buffer
== XBUFFER (w
->buffer
)
399 && NULL (w
->force_start
)
400 /* Point must be on the line that we have info recorded about */
402 && point
<= Z
- tlendpos
403 /* All text outside that line, including its final newline,
405 && (XFASTINT (w
->last_modified
) >= MODIFF
406 || (beg_unchanged
>= tlbufpos
- 1
408 && end_unchanged
>= tlendpos
409 && Z
- GPT
>= tlendpos
)))
411 if (tlbufpos
> BEGV
&& FETCH_CHAR (tlbufpos
- 1) != '\n'
413 || FETCH_CHAR (tlbufpos
) == '\n'))
414 /* Former continuation line has disappeared by becoming empty */
416 else if (XFASTINT (w
->last_modified
) < MODIFF
417 || MINI_WINDOW_P (w
))
420 overlay_arrow_seen
= 0;
421 display_text_line (w
, tlbufpos
, this_line_vpos
, this_line_start_hpos
,
422 pos_tab_offset (w
, tlbufpos
));
423 /* If line contains point, is not continued,
424 and ends at same distance from eob as before, we win */
425 if (cursor_vpos
>= 0 && this_line_bufpos
426 && this_line_endpos
== tlendpos
)
428 if (XFASTINT (w
->width
) != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w
))))
429 preserve_other_columns (w
);
435 else if (point
== XFASTINT (w
->last_point
))
439 do_pending_window_change ();
446 pos
= *compute_motion (tlbufpos
, 0,
447 XINT (w
->hscroll
) ? 1 - XINT (w
->hscroll
) : 0,
448 point
, 2, - (1 << (SHORTBITS
- 1)),
449 XFASTINT (w
->width
) - 1
450 - (XFASTINT (w
->width
) + XFASTINT (w
->left
)
451 != SCREEN_WIDTH (selected_screen
)),
452 XINT (w
->hscroll
), 0);
455 SCREEN_CURSOR_X (selected_screen
)
456 = XFASTINT (w
->left
) + max (pos
.hpos
, 0);
457 SCREEN_CURSOR_Y (selected_screen
) = this_line_vpos
;
464 /* Text changed drastically or point moved off of line */
465 cancel_line (this_line_vpos
, selected_screen
);
468 this_line_bufpos
= 0;
469 all_windows
|= buffer_shared
> 1;
476 /* Recompute # windows showing selected buffer.
477 This will be incremented each time such a window is displayed. */
480 for (tail
= Vscreen_list
; CONSP (tail
); tail
= XCONS (tail
)->cdr
)
484 if (XTYPE (XCONS (tail
)->car
) != Lisp_Screen
)
487 s
= XSCREEN (XCONS (tail
)->car
);
489 /* Redraw its windows. */
490 redisplay_windows (SCREEN_ROOT_WINDOW (s
));
493 redisplay_windows (SCREEN_ROOT_WINDOW (s
));
494 #endif /* not MULTI_SCREEN */
496 else if (SCREEN_VISIBLE_P (selected_screen
))
498 redisplay_window (selected_window
, 1);
499 if (XFASTINT (w
->width
) != SCREEN_WIDTH (selected_screen
))
500 preserve_other_columns (w
);
504 /* Prevent various kinds of signals during display update.
505 stdio is not robust about handling signals,
506 which can cause an apparent I/O error. */
518 for (tail
= Vscreen_list
; CONSP (tail
); tail
= XCONS (tail
)->cdr
)
522 if (XTYPE (XCONS (tail
)->car
) != Lisp_Screen
)
525 s
= XSCREEN (XCONS (tail
)->car
);
528 pause
|= update_screen (s
, 0, 0);
530 mark_window_display_accurate (s
->root_window
, 1);
535 #endif /* MULTI_SCREEN */
537 if (SCREEN_VISIBLE_P (selected_screen
))
538 pause
= update_screen (selected_screen
, 0, 0);
540 /* We may have called echo_area_display at the top of this
541 function. If the echo area is on another screen, that may
542 have put text on a screen other than the selected one, so the
543 above call to update_screen would not have caught it. Catch
546 SCREEN_PTR mini_screen
=
547 XSCREEN (WINDOW_SCREEN (XWINDOW (minibuf_window
)));
549 if (mini_screen
!= selected_screen
)
550 pause
|= update_screen (mini_screen
, 0, 0);
555 /* If screen does not match, prevent doing single-line-update next time.
556 Also, don't forget to check every line to update the arrow. */
559 this_line_bufpos
= 0;
560 if (!NULL (last_arrow_position
))
562 last_arrow_position
= Qt
;
563 last_arrow_string
= Qt
;
565 /* If we pause after scrolling, some lines in current_screen
566 may be null, so preserve_other_columns won't be able to
567 preserve all the vertical-bar separators. So, avoid using it
569 if (XFASTINT (w
->width
) != SCREEN_WIDTH (selected_screen
))
570 update_mode_lines
= 1;
573 /* Now text on screen agrees with windows, so
574 put info into the windows for partial redisplay to follow */
578 register struct buffer
*b
= XBUFFER (w
->buffer
);
580 blank_end_of_window
= 0;
582 unchanged_modified
= BUF_MODIFF (b
);
583 beg_unchanged
= BUF_GPT (b
) - BUF_BEG (b
);
584 end_unchanged
= BUF_Z (b
) - BUF_GPT (b
);
586 XFASTINT (w
->last_point
) = BUF_PT (b
);
587 XFASTINT (w
->last_point_x
) = SCREEN_CURSOR_X (selected_screen
);
588 XFASTINT (w
->last_point_y
) = SCREEN_CURSOR_Y (selected_screen
);
591 mark_window_display_accurate (XWINDOW (minibuf_window
)->prev
, 1);
594 w
->update_mode_line
= Qnil
;
595 XFASTINT (w
->last_modified
) = BUF_MODIFF (b
);
596 w
->window_end_valid
= Qt
;
597 last_arrow_position
= Voverlay_arrow_position
;
598 last_arrow_string
= Voverlay_arrow_string
;
600 update_mode_lines
= 0;
601 windows_or_buffers_changed
= 0;
604 /* Start SIGIO interrupts coming again.
605 Having them off during the code above
606 makes it less likely one will discard output,
607 but not impossible, since there might be stuff
608 in the system buffer here.
609 But it is much hairier to try to do anything about that. */
615 /* Change screen size now if a change is pending. */
616 do_pending_window_change ();
619 /* Redisplay, but leave alone any recent echo area message
620 unless another message has been requested in its place.
622 This is useful in situations where you need to redisplay but no
623 user action has occurred, making it inappropriate for the message
624 area to be cleared. See tracking_off and
625 wait_reading_process_input for examples of these situations. */
627 redisplay_preserve_echo_area ()
629 if (echo_area_glyphs
== 0 && previous_echo_glyphs
!= 0)
631 echo_area_glyphs
= previous_echo_glyphs
;
633 echo_area_glyphs
= 0;
640 mark_window_display_accurate (window
, flag
)
644 register struct window
*w
;
646 for (;!NULL (window
); window
= w
->next
)
648 w
= XWINDOW (window
);
650 if (!NULL (w
->buffer
))
651 XFASTINT (w
->last_modified
)
653 : XBUFFER (w
->buffer
) == current_buffer
654 ? MODIFF
: BUF_MODIFF (XBUFFER (w
->buffer
));
655 w
->window_end_valid
= Qt
;
656 w
->update_mode_line
= Qnil
;
658 if (!NULL (w
->vchild
))
659 mark_window_display_accurate (w
->vchild
, flag
);
660 if (!NULL (w
->hchild
))
661 mark_window_display_accurate (w
->hchild
, flag
);
666 last_arrow_position
= Voverlay_arrow_position
;
667 last_arrow_string
= Voverlay_arrow_string
;
671 /* t is unequal to any useful value of Voverlay_arrow_... */
672 last_arrow_position
= Qt
;
673 last_arrow_string
= Qt
;
680 redisplay_windows (window
)
683 for (; !NULL (window
); window
= XWINDOW (window
)->next
)
684 redisplay_window (window
, 0);
688 redisplay_window (window
, just_this_one
)
692 register struct window
*w
= XWINDOW (window
);
693 SCREEN_PTR s
= XSCREEN (w
->screen
);
695 register int lpoint
= point
;
696 struct buffer
*old
= current_buffer
;
697 register int width
= XFASTINT (w
->width
) - 1
698 - (XFASTINT (w
->width
) + XFASTINT (w
->left
)
699 != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w
))));
701 register int hscroll
= XINT (w
->hscroll
);
705 int window_needs_modeline
;
707 if (SCREEN_HEIGHT (s
) == 0) abort (); /* Some bug zeros some core */
709 /* If this is a combination window, do its children; that's all. */
711 if (!NULL (w
->vchild
))
713 redisplay_windows (w
->vchild
);
716 if (!NULL (w
->hchild
))
718 redisplay_windows (w
->hchild
);
721 if (NULL (w
->buffer
))
724 height
= window_internal_height (w
);
726 if (MINI_WINDOW_P (w
))
728 if (w
== XWINDOW (minibuf_window
))
730 if (echo_area_glyphs
)
731 /* We've already displayed the echo area glyphs, if any. */
736 /* This is a minibuffer, but it's not the currently active one, so
738 int vpos
= XFASTINT (XWINDOW (SCREEN_MINIBUF_WINDOW (s
))->top
);
741 for (i
= 0; i
< height
; i
++)
743 get_display_line (s
, vpos
+ i
, 0);
744 display_string (w
, vpos
+ i
, "", 0, 0, 0, width
);
751 if (update_mode_lines
)
752 w
->update_mode_line
= Qt
;
754 /* Otherwise set up data on this window; select its buffer and point value */
756 current_buffer
= XBUFFER (w
->buffer
);
759 /* Count number of windows showing the selected buffer. */
762 && current_buffer
== XBUFFER (XWINDOW (selected_window
)->buffer
))
765 /* POINT refers normally to the selected window.
766 For any other window, set up appropriate value. */
768 if (!EQ (window
, selected_window
))
770 SET_PT (marker_position (w
->pointm
));
774 Fset_marker (w
->pointm
, make_number (point
), Qnil
);
776 else if (point
> (ZV
- 1))
779 Fset_marker (w
->pointm
, make_number (point
), Qnil
);
783 /* If window-start is screwed up, choose a new one. */
784 if (XMARKER (w
->start
)->buffer
!= current_buffer
)
787 startp
= marker_position (w
->start
);
789 /* Handle case where place to start displaying has been specified,
790 unless the specified location is outside the visible range. */
791 if (!NULL (w
->force_start
))
793 w
->update_mode_line
= Qt
;
794 w
->force_start
= Qnil
;
795 XFASTINT (w
->last_modified
) = 0;
796 if (startp
< BEGV
) startp
= BEGV
;
797 if (startp
> ZV
) startp
= ZV
;
798 try_window (window
, startp
);
801 /* If point does not appear, move point so it does appear */
802 pos
= *compute_motion (startp
, 0,
803 ((EQ (window
, minibuf_window
) && startp
== 1)
804 ? minibuf_prompt_width
: 0)
806 (hscroll
? 1 - hscroll
: 0),
808 - (1 << (SHORTBITS
- 1)),
809 width
, hscroll
, pos_tab_offset (w
, startp
));
811 if (w
!= XWINDOW (SCREEN_SELECTED_WINDOW (s
)))
812 Fset_marker (w
->pointm
, make_number (point
), Qnil
);
816 SCREEN_CURSOR_X (s
) = max (0, pos
.hpos
) + XFASTINT (w
->left
);
817 SCREEN_CURSOR_Y (s
) = pos
.vpos
+ XFASTINT (w
->top
);
823 /* Handle case where text has not changed, only point,
824 and it has not moved off the screen */
826 /* This code is not used for minibuffer for the sake of
827 the case of redisplaying to replace an echo area message;
828 since in that case the minibuffer contents per se are usually unchanged.
829 This code is of no real use in the minibuffer since
830 the handling of this_line_bufpos, etc.,
831 in redisplay handles the same cases. */
833 if (XFASTINT (w
->last_modified
) >= MODIFF
834 && point
>= startp
&& !clip_changed
835 && (just_this_one
|| XFASTINT (w
->width
) == SCREEN_WIDTH (s
))
836 && !EQ (window
, minibuf_window
))
838 pos
= *compute_motion (startp
, 0, (hscroll
? 1 - hscroll
: 0),
839 point
, height
+ 1, 10000, width
, hscroll
,
840 pos_tab_offset (w
, startp
));
842 if (pos
.vpos
< height
)
844 /* Ok, point is still on screen */
845 if (w
== XWINDOW (SCREEN_SELECTED_WINDOW (s
)))
847 /* These variables are supposed to be origin 1 */
848 SCREEN_CURSOR_X (s
) = max (0, pos
.hpos
) + XFASTINT (w
->left
);
849 SCREEN_CURSOR_Y (s
) = pos
.vpos
+ XFASTINT (w
->top
);
851 /* This doesn't do the trick, because if a window to the right of
852 this one must be redisplayed, this does nothing because there
853 is nothing in DesiredScreen yet, and then the other window is
854 redisplayed, making likes that are empty in this window's columns.
855 if (XFASTINT (w->width) != SCREEN_WIDTH (s))
856 preserve_my_columns (w);
860 /* Don't bother trying redisplay with same start;
861 we already know it will lose */
863 /* If current starting point was originally the beginning of a line
864 but no longer is, find a new starting point. */
865 else if (!NULL (w
->start_at_line_beg
)
867 || FETCH_CHAR (startp
- 1) == '\n'))
871 else if (just_this_one
&& !MINI_WINDOW_P (w
)
873 && XFASTINT (w
->last_modified
)
874 && ! EQ (w
->window_end_valid
, Qnil
)
875 && do_id
&& !clip_changed
876 && !blank_end_of_window
877 && XFASTINT (w
->width
) == SCREEN_WIDTH (s
)
878 && EQ (last_arrow_position
, Voverlay_arrow_position
)
879 && EQ (last_arrow_string
, Voverlay_arrow_string
)
880 && (tem
= try_window_id (SCREEN_SELECTED_WINDOW (s
)))
883 /* tem > 0 means success. tem == -1 means choose new start.
884 tem == -2 means try again with same start,
885 and nothing but whitespace follows the changed stuff.
886 tem == 0 means try again with same start. */
890 else if (startp
>= BEGV
&& startp
<= ZV
891 /* Avoid starting display at end of buffer! */
892 && (startp
< ZV
|| startp
== BEGV
893 || (XFASTINT (w
->last_modified
) >= MODIFF
)))
895 /* Try to redisplay starting at same place as before */
896 /* If point has not moved off screen, accept the results */
897 try_window (window
, startp
);
898 if (cursor_vpos
>= 0)
901 cancel_my_columns (w
);
904 XFASTINT (w
->last_modified
) = 0;
905 w
->update_mode_line
= Qt
;
907 /* Try to scroll by specified few lines */
909 if (scroll_step
&& !clip_changed
)
913 pos
= *vmotion (Z
- XFASTINT (w
->window_end_pos
),
914 scroll_step
, width
, hscroll
, window
);
915 if (pos
.vpos
>= height
)
919 pos
= *vmotion (startp
, point
< startp
? - scroll_step
: scroll_step
,
920 width
, hscroll
, window
);
922 if (point
>= pos
.bufpos
)
924 try_window (window
, pos
.bufpos
);
925 if (cursor_vpos
>= 0)
928 cancel_my_columns (w
);
933 /* Finally, just choose place to start which centers point */
936 pos
= *vmotion (point
, - height
/ 2, width
, hscroll
, window
);
937 try_window (window
, pos
.bufpos
);
939 startp
= marker_position (w
->start
);
940 w
->start_at_line_beg
=
941 (startp
== BEGV
|| FETCH_CHAR (startp
- 1) == '\n') ? Qt
: Qnil
;
944 /* If window not full width, must redo its mode line
945 if the window to its side is being redone */
946 if ((!NULL (w
->update_mode_line
)
947 || (!just_this_one
&& width
< SCREEN_WIDTH (s
) - 1))
948 && height
!= XFASTINT (w
->height
))
949 display_mode_line (w
);
952 current_buffer
= old
;
956 /* Do full redisplay on one window, starting at position `pos'. */
959 try_window (window
, pos
)
963 register struct window
*w
= XWINDOW (window
);
964 register int height
= window_internal_height (w
);
965 register int vpos
= XFASTINT (w
->top
);
966 register int last_text_vpos
= vpos
;
967 int tab_offset
= pos_tab_offset (w
, pos
);
968 SCREEN_PTR s
= XSCREEN (w
->screen
);
969 int width
= XFASTINT (w
->width
) - 1
970 - (XFASTINT (w
->width
) + XFASTINT (w
->left
) != SCREEN_WIDTH (s
));
973 Fset_marker (w
->start
, make_number (pos
), Qnil
);
975 overlay_arrow_seen
= 0;
976 val
.hpos
= XINT (w
->hscroll
) ? 1 - XINT (w
->hscroll
) : 0;
978 while (--height
>= 0)
980 val
= *display_text_line (w
, pos
, vpos
, val
.hpos
, tab_offset
);
982 if (val
.vpos
) tab_offset
= 0;
984 if (pos
!= val
.bufpos
)
986 /* Next line, unless prev line ended in end of buffer with no cr */
987 = vpos
- (val
.vpos
&& FETCH_CHAR (val
.bufpos
- 1) != '\n');
991 /* If last line is continued in middle of character,
992 include the split character in the text considered on the screen */
993 if (val
.hpos
< (XINT (w
->hscroll
) ? 1 - XINT (w
->hscroll
) : 0))
996 /* If bottom just moved off end of screen, change mode line percentage. */
997 if (XFASTINT (w
->window_end_pos
) == 0
999 w
->update_mode_line
= Qt
;
1001 /* Say where last char on screen will be, once redisplay is finished. */
1002 XFASTINT (w
->window_end_pos
) = Z
- pos
;
1003 XFASTINT (w
->window_end_vpos
) = last_text_vpos
- XFASTINT (w
->top
);
1004 /* But that is not valid info until redisplay finishes. */
1005 w
->window_end_valid
= Qnil
;
1008 /* Try to redisplay when buffer is modified locally,
1009 computing insert/delete line to preserve text outside
1010 the bounds of the changes.
1011 Return 1 if successful, 0 if if cannot tell what to do,
1012 or -1 to tell caller to find a new window start,
1013 or -2 to tell caller to do normal redisplay with same window start. */
1016 try_window_id (window
)
1020 register struct window
*w
= XWINDOW (window
);
1021 register int height
= window_internal_height (w
);
1022 SCREEN_PTR s
= XSCREEN (w
->screen
);
1023 int top
= XFASTINT (w
->top
);
1024 int start
= marker_position (w
->start
);
1025 int width
= XFASTINT (w
->width
) - 1
1026 - (XFASTINT (w
->width
) + XFASTINT (w
->left
) != SCREEN_WIDTH (s
));
1027 int hscroll
= XINT (w
->hscroll
);
1028 int lmargin
= hscroll
> 0 ? 1 - hscroll
: 0;
1030 register int i
, tem
;
1031 int last_text_vpos
= 0;
1034 struct position val
, bp
, ep
, xp
, pp
;
1035 int scroll_amount
= 0;
1037 int tab_offset
, epto
;
1039 if (GPT
- BEG
< beg_unchanged
)
1040 beg_unchanged
= GPT
- BEG
;
1041 if (Z
- GPT
< end_unchanged
)
1042 end_unchanged
= Z
- GPT
;
1044 if (beg_unchanged
+ 1 < start
)
1045 return 0; /* Give up if changes go above top of window */
1047 /* Find position before which nothing is changed. */
1048 bp
= *compute_motion (start
, 0, lmargin
,
1049 beg_unchanged
+ 1, height
+ 1, 0, width
, hscroll
,
1050 pos_tab_offset (w
, start
));
1051 if (bp
.vpos
>= height
)
1053 if (point
< bp
.bufpos
&& !bp
.contin
)
1055 /* All changes are below the screen, and point is on the screen.
1056 We don't need to change the screen at all.
1057 But we need to update window_end_pos to account for
1058 any change in buffer size. */
1059 bp
= *compute_motion (start
, 0, lmargin
,
1061 width
, hscroll
, pos_tab_offset (w
, start
));
1062 XFASTINT (w
->window_end_vpos
) = height
;
1063 XFASTINT (w
->window_end_pos
) = Z
- bp
.bufpos
;
1071 /* Find beginning of that screen line. Must display from there. */
1072 bp
= *vmotion (bp
.bufpos
, 0, width
, hscroll
, window
);
1079 /* If about to start displaying at the beginning of a continuation line,
1080 really start with previous screen line, in case it was not
1081 continued when last redisplayed */
1082 if (bp
.contin
&& bp
.bufpos
- 1 == beg_unchanged
&& vpos
> 0)
1084 bp
= *vmotion (bp
.bufpos
, -1, width
, hscroll
, window
);
1089 if (bp
.contin
&& bp
.hpos
!= lmargin
)
1091 val
.hpos
= bp
.prevhpos
- width
+ lmargin
;
1097 /* Find first visible newline after which no more is changed. */
1098 tem
= find_next_newline (Z
- max (end_unchanged
, Z
- ZV
), 1);
1099 if (XTYPE (current_buffer
->selective_display
) == Lisp_Int
1100 && XINT (current_buffer
->selective_display
) > 0)
1102 && (position_indentation (tem
)
1103 >= XINT (current_buffer
->selective_display
)))
1104 tem
= find_next_newline (tem
, 1);
1106 /* Compute the cursor position after that newline. */
1107 ep
= *compute_motion (pos
, vpos
, val
.hpos
, tem
,
1108 height
, - (1 << (SHORTBITS
- 1)),
1109 width
, hscroll
, pos_tab_offset (w
, bp
.bufpos
));
1111 /* If changes reach past the text available on the screen,
1112 just display rest of screen. */
1113 if (ep
.bufpos
> Z
- XFASTINT (w
->window_end_pos
))
1116 stop_vpos
= ep
.vpos
;
1118 /* If no newline before ep, the line ep is on includes some changes
1119 that must be displayed. Make sure we don't stop before it. */
1120 /* Also, if changes reach all the way until ep.bufpos,
1121 it is possible that something was deleted after the
1122 newline before it, so the following line must be redrawn. */
1123 if (stop_vpos
== ep
.vpos
1124 && (ep
.bufpos
== BEGV
1125 || FETCH_CHAR (ep
.bufpos
- 1) != '\n'
1126 || ep
.bufpos
== Z
- end_unchanged
))
1127 stop_vpos
= ep
.vpos
+ 1;
1130 overlay_arrow_seen
= 0;
1132 /* If changes do not reach to bottom of window,
1133 figure out how much to scroll the rest of the window */
1134 if (stop_vpos
< height
)
1136 /* Now determine how far up or down the rest of the window has moved */
1137 epto
= pos_tab_offset (w
, ep
.bufpos
);
1138 xp
= *compute_motion (ep
.bufpos
, ep
.vpos
, ep
.hpos
,
1139 Z
- XFASTINT (w
->window_end_pos
),
1140 10000, 0, width
, hscroll
, epto
);
1141 scroll_amount
= xp
.vpos
- XFASTINT (w
->window_end_vpos
);
1143 /* Is everything on screen below the changes whitespace?
1144 If so, no scrolling is really necessary. */
1145 for (i
= ep
.bufpos
; i
< xp
.bufpos
; i
++)
1147 tem
= FETCH_CHAR (i
);
1148 if (tem
!= ' ' && tem
!= '\n' && tem
!= '\t')
1154 XFASTINT (w
->window_end_vpos
) += scroll_amount
;
1156 /* Before doing any scrolling, verify that point will be on screen. */
1157 if (point
> ep
.bufpos
&& !(point
<= xp
.bufpos
&& xp
.bufpos
< height
))
1159 if (point
<= xp
.bufpos
)
1161 pp
= *compute_motion (ep
.bufpos
, ep
.vpos
, ep
.hpos
,
1162 point
, height
, - (1 << (SHORTBITS
- 1)),
1163 width
, hscroll
, epto
);
1167 pp
= *compute_motion (xp
.bufpos
, xp
.vpos
, xp
.hpos
,
1168 point
, height
, - (1 << (SHORTBITS
- 1)),
1169 width
, hscroll
, pos_tab_offset (w
, xp
.bufpos
));
1171 if (pp
.bufpos
< point
|| pp
.vpos
== height
)
1173 cursor_vpos
= pp
.vpos
+ top
;
1174 cursor_hpos
= pp
.hpos
+ XFASTINT (w
->left
);
1177 if (stop_vpos
- scroll_amount
>= height
1178 || ep
.bufpos
== xp
.bufpos
)
1180 if (scroll_amount
< 0)
1181 stop_vpos
-= scroll_amount
;
1183 /* In this path, we have altered window_end_vpos
1184 and not left it negative.
1185 We must make sure that, in case display is preempted
1186 before the screen changes to reflect what we do here,
1187 further updates will not come to try_window_id
1188 and assume the screen and window_end_vpos match. */
1189 blank_end_of_window
= 1;
1191 else if (!scroll_amount
)
1193 else if (bp
.bufpos
== Z
- end_unchanged
)
1195 /* If reprinting everything is nearly as fast as scrolling,
1196 don't bother scrolling. Can happen if lines are short. */
1197 if (scroll_cost (s
, bp
.vpos
+ top
- scroll_amount
,
1198 top
+ height
- max (0, scroll_amount
),
1200 > xp
.bufpos
- bp
.bufpos
- 20)
1201 /* Return "try normal display with same window-start."
1202 Too bad we can't prevent further scroll-thinking. */
1204 /* If pure deletion, scroll up as many lines as possible.
1205 In common case of killing a line, this can save the
1206 following line from being overwritten by scrolling
1207 and therefore having to be redrawn. */
1208 tem
= scroll_screen_lines (s
, bp
.vpos
+ top
- scroll_amount
,
1209 top
+ height
- max (0, scroll_amount
),
1211 if (!tem
) stop_vpos
= height
;
1213 else if (scroll_amount
)
1215 /* If reprinting everything is nearly as fast as scrolling,
1216 don't bother scrolling. Can happen if lines are short. */
1217 /* Note that if scroll_amount > 0, xp.bufpos - bp.bufpos is an
1218 overestimate of cost of reprinting, since xp.bufpos
1219 would end up below the bottom of the window. */
1220 if (scroll_cost (s
, ep
.vpos
+ top
- scroll_amount
,
1221 top
+ height
- max (0, scroll_amount
),
1223 > xp
.bufpos
- ep
.bufpos
- 20)
1224 /* Return "try normal display with same window-start."
1225 Too bad we can't prevent further scroll-thinking. */
1227 tem
= scroll_screen_lines (s
, ep
.vpos
+ top
- scroll_amount
,
1228 top
+ height
- max (0, scroll_amount
),
1230 if (!tem
) stop_vpos
= height
;
1234 /* In any case, do not display past bottom of window */
1235 if (stop_vpos
>= height
)
1241 /* Handle case where pos is before w->start --
1242 can happen if part of line had been clipped and is not clipped now */
1243 if (vpos
== 0 && pos
< marker_position (w
->start
))
1244 Fset_marker (w
->start
, make_number (pos
), Qnil
);
1246 /* Redisplay the lines where the text was changed */
1247 last_text_vpos
= vpos
;
1248 tab_offset
= pos_tab_offset (w
, pos
);
1249 /* If we are starting display in mid-character, correct tab_offset
1250 to account for passing the line that that character really starts in. */
1251 if (val
.hpos
< lmargin
)
1252 tab_offset
+= width
;
1253 while (vpos
< stop_vpos
)
1255 val
= *display_text_line (w
, pos
, top
+ vpos
++, val
.hpos
, tab_offset
);
1256 tab_offset
+= width
;
1257 if (val
.vpos
) tab_offset
= 0;
1258 if (pos
!= val
.bufpos
)
1260 /* Next line, unless prev line ended in end of buffer with no cr */
1261 = vpos
- (val
.vpos
&& FETCH_CHAR (val
.bufpos
- 1) != '\n');
1265 /* There are two cases:
1266 1) we have displayed down to the bottom of the window
1267 2) we have scrolled lines below stop_vpos by scroll_amount */
1271 /* If last line is continued in middle of character,
1272 include the split character in the text considered on the screen */
1273 if (val
.hpos
< lmargin
)
1275 XFASTINT (w
->window_end_vpos
) = last_text_vpos
;
1276 XFASTINT (w
->window_end_pos
) = Z
- val
.bufpos
;
1279 /* If scrolling made blank lines at window bottom,
1280 redisplay to fill those lines */
1281 if (scroll_amount
< 0)
1283 /* Don't consider these lines for general-purpose scrolling.
1284 That will save time in the scrolling computation. */
1285 SCREEN_SCROLL_BOTTOM_VPOS (s
) = xp
.vpos
;
1290 vpos
= height
+ scroll_amount
;
1291 else if (xp
.contin
&& xp
.hpos
!= lmargin
)
1293 val
.hpos
= xp
.prevhpos
- width
+ lmargin
;
1297 blank_end_of_window
= 1;
1298 tab_offset
= pos_tab_offset (w
, pos
);
1299 /* If we are starting display in mid-character, correct tab_offset
1300 to account for passing the line that that character starts in. */
1301 if (val
.hpos
< lmargin
)
1302 tab_offset
+= width
;
1304 while (vpos
< height
)
1306 val
= *display_text_line (w
, pos
, top
+ vpos
++, val
.hpos
, tab_offset
);
1307 tab_offset
+= width
;
1308 if (val
.vpos
) tab_offset
= 0;
1312 /* Here is a case where display_text_line sets cursor_vpos wrong.
1313 Make it be fixed up, below. */
1315 && xp
.bufpos
== point
)
1319 /* If bottom just moved off end of screen, change mode line percentage. */
1320 if (XFASTINT (w
->window_end_pos
) == 0
1322 w
->update_mode_line
= Qt
;
1324 /* Attempt to adjust end-of-text positions to new bottom line */
1327 delta
= height
- xp
.vpos
;
1329 || (delta
> 0 && xp
.bufpos
<= ZV
)
1330 || (delta
== 0 && xp
.hpos
))
1332 val
= *vmotion (Z
- XFASTINT (w
->window_end_pos
),
1333 delta
, width
, hscroll
, window
);
1334 XFASTINT (w
->window_end_pos
) = Z
- val
.bufpos
;
1335 XFASTINT (w
->window_end_vpos
) += val
.vpos
;
1339 w
->window_end_valid
= Qnil
;
1341 /* If point was not in a line that was displayed, find it */
1342 if (cursor_vpos
< 0)
1344 val
= *compute_motion (start
, 0, lmargin
, point
, 10000, 10000,
1345 width
, hscroll
, pos_tab_offset (w
, start
));
1346 /* Admit failure if point is off screen now */
1347 if (val
.vpos
>= height
)
1349 for (vpos
= 0; vpos
< height
; vpos
++)
1350 cancel_line (vpos
+ top
, s
);
1353 cursor_vpos
= val
.vpos
+ top
;
1354 cursor_hpos
= val
.hpos
+ XFASTINT (w
->left
);
1357 SCREEN_CURSOR_X (s
) = max (0, cursor_hpos
);
1358 SCREEN_CURSOR_Y (s
) = cursor_vpos
;
1362 val
= *compute_motion (start
, 0, lmargin
, ZV
,
1363 height
, - (1 << (SHORTBITS
- 1)),
1364 width
, hscroll
, pos_tab_offset (w
, start
));
1365 if (val
.vpos
!= XFASTINT (w
->window_end_vpos
))
1367 if (XFASTINT (w
->window_end_pos
)
1375 /* Copy glyphs from the rope FROM to T.
1376 But don't actually copy the parts that would come in before S.
1377 Value is T, advanced past the copied data.
1379 Characters in FROM are grouped into units of `sizeof GLYPH' chars;
1380 any extra chars at the end of FROM are ignored. */
1383 copy_rope (t
, s
, from
)
1384 register GLYPH
*t
; /* Copy to here. */
1385 register GLYPH
*s
; /* Starting point. */
1386 Lisp_Object from
; /* Data to copy; known to be a string. */
1388 register int n
= XSTRING (from
)->size
/ sizeof (GLYPH
);
1389 register GLYPH
*f
= (GLYPH
*) XSTRING (from
)->data
;
1393 if (t
>= s
) *t
= *f
;
1400 /* Display one line of window w, starting at position START in W's buffer.
1401 Display starting at horizontal position HPOS, which is normally zero
1402 or negative. A negative value causes output up to hpos = 0 to be discarded.
1403 This is done for negative hscroll, or when this is a continuation line
1404 and the continuation occurred in the middle of a multi-column character.
1406 TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
1408 Display on position VPOS on the screen. (origin 0).
1410 Returns a STRUCT POSITION giving character to start next line with
1411 and where to display it, including a zero or negative hpos.
1412 The vpos field is not really a vpos; it is 1 unless the line is continued */
1414 struct position val_display_text_line
;
1416 static struct position
*
1417 display_text_line (w
, start
, vpos
, hpos
, taboffset
)
1424 register int pos
= start
;
1429 register unsigned char *p
;
1431 register GLYPH
*startp
;
1432 register GLYPH
*p1prev
;
1433 SCREEN_PTR s
= XSCREEN (w
->screen
);
1434 int tab_width
= XINT (current_buffer
->tab_width
);
1435 int ctl_arrow
= !NULL (current_buffer
->ctl_arrow
);
1436 int width
= XFASTINT (w
->width
) - 1
1437 - (XFASTINT (w
->width
) + XFASTINT (w
->left
) != SCREEN_WIDTH (s
));
1438 struct position val
;
1441 int hscroll
= XINT (w
->hscroll
);
1442 int truncate
= hscroll
1443 || (truncate_partial_width_windows
1444 && XFASTINT (w
->width
) < SCREEN_WIDTH (s
))
1445 || !NULL (current_buffer
->truncate_lines
);
1447 = XTYPE (current_buffer
->selective_display
) == Lisp_Int
1448 ? XINT (current_buffer
->selective_display
)
1449 : !NULL (current_buffer
->selective_display
) ? -1 : 0;
1451 int selective_e
= selective
&& !NULL (current_buffer
->selective_display_ellipses
);
1453 register struct screen_glyphs
*desired_glyphs
= SCREEN_DESIRED_GLYPHS (s
);
1454 register struct Lisp_Vector
*dp
= window_display_table (w
);
1456 = (selective
&& dp
&& XTYPE (DISP_INVIS_ROPE (dp
)) == Lisp_String
1457 ? XSTRING (DISP_INVIS_ROPE (dp
))->size
/ sizeof (GLYPH
) : 0);
1458 GLYPH truncator
= (dp
== 0 || XTYPE (DISP_TRUNC_GLYPH (dp
)) != Lisp_Int
1459 ? '$' : XINT (DISP_TRUNC_GLYPH (dp
)));
1460 GLYPH continuer
= (dp
== 0 || XTYPE (DISP_CONTINUE_GLYPH (dp
)) != Lisp_Int
1461 ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp
)));
1463 hpos
+= XFASTINT (w
->left
);
1464 get_display_line (s
, vpos
, XFASTINT (w
->left
));
1465 if (tab_width
<= 0 || tab_width
> 20) tab_width
= 8;
1467 if (MINI_WINDOW_P (w
) && start
== 1
1468 && vpos
== XFASTINT (w
->top
))
1471 hpos
= display_string (w
, vpos
, minibuf_prompt
, hpos
,
1472 (!truncate
? continuer
: truncator
),
1474 minibuf_prompt_width
= hpos
;
1477 desired_glyphs
->bufp
[vpos
] = pos
;
1478 p1
= desired_glyphs
->glyphs
[vpos
] + hpos
;
1480 startp
= desired_glyphs
->glyphs
[vpos
] + XFASTINT (w
->left
);
1481 endp
= startp
+ width
;
1483 /* Loop generating characters.
1484 Stop at end of buffer, before newline,
1485 or if reach or pass continuation column. */
1495 if (pos
== point
&& cursor_vpos
< 0)
1498 cursor_hpos
= p1
- startp
;
1502 if (pos
< point
&& point
< pause
)
1504 if (pos
< GPT
&& GPT
< pause
)
1507 p
= &FETCH_CHAR (pos
);
1510 if (c
>= 040 && c
< 0177
1511 && (dp
== 0 || XTYPE (DISP_CHAR_ROPE (dp
, c
)) != Lisp_String
))
1522 && position_indentation (pos
+ 1) >= selective
)
1525 pos
= find_next_newline (pos
+ 1, 1);
1526 if (FETCH_CHAR (pos
- 1) == '\n')
1529 if (invis
&& selective_rlen
> 0 && p1
>= startp
)
1531 p1
+= selective_rlen
;
1532 if (p1
- startp
> width
)
1534 bcopy (XSTRING (DISP_INVIS_ROPE (dp
))->data
, p1prev
,
1535 (p1
- p1prev
) * sizeof (GLYPH
));
1543 if (p1
>= startp
&& p1
< endp
)
1547 while ((p1
- startp
+ taboffset
+ hscroll
- (hscroll
> 0))
1550 else if (c
== Ctl ('M') && selective
== -1)
1552 pos
= find_next_newline (pos
, 1);
1553 if (FETCH_CHAR (pos
- 1) == '\n')
1555 if (selective_rlen
> 0)
1557 p1
+= selective_rlen
;
1558 if (p1
- startp
> width
)
1560 bcopy (XSTRING (DISP_INVIS_ROPE (dp
))->data
, p1prev
,
1561 (p1
- p1prev
) * sizeof (GLYPH
));
1565 else if (dp
!= 0 && XTYPE (DISP_CHAR_ROPE (dp
, c
)) == Lisp_String
)
1567 p1
= copy_rope (p1
, startp
, DISP_CHAR_ROPE (dp
, c
));
1569 else if (c
< 0200 && ctl_arrow
)
1572 *p1
= (dp
&& XTYPE (DISP_CTRL_GLYPH (dp
)) == Lisp_Int
1573 ? XINT (DISP_CTRL_GLYPH (dp
)) : '^');
1575 if (p1
>= startp
&& p1
< endp
)
1582 *p1
= (dp
&& XTYPE (DISP_ESCAPE_GLYPH (dp
)) == Lisp_Int
1583 ? XINT (DISP_ESCAPE_GLYPH (dp
)) : '\\');
1585 if (p1
>= startp
&& p1
< endp
)
1586 *p1
= (c
>> 6) + '0';
1588 if (p1
>= startp
&& p1
< endp
)
1589 *p1
= (7 & (c
>> 3)) + '0';
1591 if (p1
>= startp
&& p1
< endp
)
1592 *p1
= (7 & c
) + '0';
1598 val
.hpos
= - XINT (w
->hscroll
);
1606 /* Handle continuation in middle of a character */
1607 /* by backing up over it */
1610 /* Start the next line with that same character */
1612 /* but at a negative hpos, to skip the columns output on this line. */
1613 val
.hpos
+= p1prev
- endp
;
1614 /* Keep in this line everything up to the continuation column. */
1618 /* Finish deciding which character to start the next line on,
1619 and what hpos to start it at.
1620 Also set `lastpos' to the last position which counts as "on this line"
1621 for cursor-positioning. */
1625 if (FETCH_CHAR (pos
) == '\n')
1626 /* If stopped due to a newline, start next line after it */
1629 /* Stopped due to right margin of window */
1634 /* Truncating => start next line after next newline,
1635 and point is on this line if it is before the newline,
1636 and skip none of first char of next line */
1637 pos
= find_next_newline (pos
, 1);
1638 val
.hpos
= XINT (w
->hscroll
) ? 1 - XINT (w
->hscroll
) : 0;
1640 lastpos
= pos
- (FETCH_CHAR (pos
- 1) == '\n');
1651 /* If point is at eol or in invisible text at eol,
1652 record its screen location now. */
1654 if (start
<= point
&& point
<= lastpos
&& cursor_vpos
< 0)
1657 cursor_hpos
= p1
- startp
;
1660 if (cursor_vpos
== vpos
)
1662 if (cursor_hpos
< 0) cursor_hpos
= 0;
1663 if (cursor_hpos
> width
) cursor_hpos
= width
;
1664 cursor_hpos
+= XFASTINT (w
->left
);
1665 if (w
== XWINDOW (SCREEN_SELECTED_WINDOW (s
)))
1667 SCREEN_CURSOR_Y (s
) = cursor_vpos
;
1668 SCREEN_CURSOR_X (s
) = cursor_hpos
;
1670 if (w
== XWINDOW (selected_window
))
1672 /* Line is not continued and did not start
1673 in middle of character */
1674 if ((hpos
- XFASTINT (w
->left
)
1675 == (XINT (w
->hscroll
) ? 1 - XINT (w
->hscroll
) : 0))
1678 this_line_bufpos
= start
;
1679 this_line_buffer
= current_buffer
;
1680 this_line_vpos
= cursor_vpos
;
1681 this_line_start_hpos
= hpos
;
1682 this_line_endpos
= Z
- lastpos
;
1685 this_line_bufpos
= 0;
1690 /* If hscroll and line not empty, insert truncation-at-left marker */
1691 if (hscroll
&& lastpos
!= start
)
1693 *startp
= truncator
;
1698 if (XFASTINT (w
->width
) + XFASTINT (w
->left
) != SCREEN_WIDTH (s
))
1701 if (p1
< startp
) p1
= startp
;
1702 while (p1
< endp
) *p1
++ = SPACEGLYPH
;
1705 desired_glyphs
->used
[vpos
] = max (desired_glyphs
->used
[vpos
],
1706 p1
- desired_glyphs
->glyphs
[vpos
]);
1707 desired_glyphs
->glyphs
[vpos
][desired_glyphs
->used
[vpos
]] = 0;
1709 /* If the start of this line is the overlay arrow-position,
1710 then put the arrow string into the display-line. */
1712 if (XTYPE (Voverlay_arrow_position
) == Lisp_Marker
1713 && current_buffer
== XMARKER (Voverlay_arrow_position
)->buffer
1714 && start
== marker_position (Voverlay_arrow_position
)
1715 && XTYPE (Voverlay_arrow_string
) == Lisp_String
1716 && ! overlay_arrow_seen
)
1718 unsigned char *p
= XSTRING (Voverlay_arrow_string
)->data
;
1720 int len
= XSTRING (Voverlay_arrow_string
)->size
;
1722 if (len
> XFASTINT (w
->width
) - 1)
1723 len
= XFASTINT (w
->width
) - 1;
1724 for (i
= 0; i
< len
; i
++)
1726 if (desired_glyphs
->used
[vpos
] <
1727 (len
+ startp
- desired_glyphs
->glyphs
[vpos
]))
1728 desired_glyphs
->used
[vpos
] = len
+ startp
- desired_glyphs
->glyphs
[vpos
];
1730 overlay_arrow_seen
= 1;
1734 val_display_text_line
= val
;
1735 return &val_display_text_line
;
1738 /* Display the mode line for window w */
1741 display_mode_line (w
)
1744 register int vpos
= XFASTINT (w
->height
) + XFASTINT (w
->top
) - 1;
1745 register int left
= XFASTINT (w
->left
);
1746 register int right
= XFASTINT (w
->width
) + left
;
1747 register SCREEN_PTR s
= XSCREEN (WINDOW_SCREEN (w
));
1749 get_display_line (s
, vpos
, left
);
1750 display_mode_element (w
, vpos
, left
, 0, right
, right
,
1751 current_buffer
->mode_line_format
);
1752 SCREEN_DESIRED_GLYPHS (s
)->bufp
[vpos
] = 0;
1754 /* Make the mode line inverse video if the entire line
1755 is made of mode lines.
1756 I.e. if this window is full width,
1757 or if it is the child of a full width window
1758 (which implies that that window is split side-by-side
1759 and the rest of this line is mode lines of the sibling windows). */
1760 if (XFASTINT (w
->width
) == SCREEN_WIDTH (s
)
1761 || XFASTINT (XWINDOW (w
->parent
)->width
) == SCREEN_WIDTH (s
))
1762 s
->desired_glyphs
->highlight
[vpos
] = mode_line_inverse_video
;
1764 #ifdef HAVE_X_WINDOWS
1765 /* I'm trying this out because I saw Unimpress use it, but it's
1766 possible that this may mess adversely with some window managers. jla */
1769 && ! SCREEN_MINIBUF_ONLY_P (s
)
1770 && w
== XWINDOW (s
->selected_window
)
1771 && (NULL (Fstring_equal (XBUFFER (w
->buffer
)->name
, s
->name
))))
1772 x_set_name (s
, XBUFFER (w
->buffer
)->name
, Qnil
);
1776 /* Contribute ELT to the mode line for window W.
1777 How it translates into text depends on its data type.
1779 VPOS is the position of the mode line being displayed.
1781 HPOS is the position (absolute on screen) where this element's text
1782 should start. The output is truncated automatically at the right
1785 DEPTH is the depth in recursion. It is used to prevent
1786 infinite recursion here.
1788 MINENDCOL is the hpos before which the element may not end.
1789 The element is padded at the right with spaces if nec
1790 to reach this column.
1792 MAXENDCOL is the hpos past which this element may not extend.
1793 If MINENDCOL is > MAXENDCOL, MINENDCOL takes priority.
1794 (This is necessary to make nested padding and truncation work.)
1796 Returns the hpos of the end of the text generated by ELT.
1797 The next element will receive that value as its HPOS arg,
1798 so as to concatenate the elements. */
1801 display_mode_element (w
, vpos
, hpos
, depth
, minendcol
, maxendcol
, elt
)
1803 register int vpos
, hpos
;
1806 register int maxendcol
;
1807 register Lisp_Object elt
;
1815 #ifdef SWITCH_ENUM_BUG
1816 switch ((int) XTYPE (elt
))
1818 switch (XTYPE (elt
))
1823 /* A string: output it and check for %-constructs within it. */
1824 register unsigned char c
;
1825 register unsigned char *this = XSTRING (elt
)->data
;
1827 while (hpos
< maxendcol
&& *this)
1829 unsigned char *last
= this;
1830 while ((c
= *this++) != '\0' && c
!= '%')
1832 if (this - 1 != last
)
1834 register int lim
= --this - last
+ hpos
;
1835 hpos
= display_string (w
, vpos
, last
, hpos
, 0, hpos
,
1836 min (lim
, maxendcol
));
1840 register int spec_width
= 0;
1842 /* We can't allow -ve args due to the "%-" construct */
1843 /* Argument specifies minwidth but not maxwidth
1844 (maxwidth can be specified by
1845 (<negative-number> . <stuff>) mode-line elements) */
1847 while ((c
= *this++) >= '0' && c
<= '9')
1849 spec_width
= spec_width
* 10 + (c
- '0');
1853 if (spec_width
> maxendcol
)
1854 spec_width
= maxendcol
;
1857 hpos
= display_mode_element (w
, vpos
, hpos
, depth
,
1858 spec_width
, maxendcol
,
1859 Vglobal_mode_string
);
1861 hpos
= display_string (w
, vpos
,
1862 decode_mode_spec (w
, c
,
1864 hpos
, 0, spec_width
, maxendcol
);
1871 /* A symbol: process the value of the symbol recursively
1872 as if it appeared here directly. Avoid error if symbol void.
1873 Special case: if value of symbol is a string, output the string
1876 register Lisp_Object tem
;
1877 tem
= Fboundp (elt
);
1880 tem
= Fsymbol_value (elt
);
1881 /* If value is a string, output that string literally:
1882 don't check for % within it. */
1883 if (XTYPE (tem
) == Lisp_String
)
1884 hpos
= display_string (w
, vpos
, XSTRING (tem
)->data
,
1885 hpos
, 0, minendcol
, maxendcol
);
1886 /* Give up right away for nil or t. */
1887 else if (!EQ (tem
, elt
))
1888 { elt
= tem
; goto tail_recurse
; }
1895 register Lisp_Object car
, tem
;
1897 /* A cons cell: three distinct cases.
1898 If first element is a string or a cons, process all the elements
1899 and effectively concatenate them.
1900 If first element is a negative number, truncate displaying cdr to
1901 at most that many characters. If positive, pad (with spaces)
1902 to at least that many characters.
1903 If first element is a symbol, process the cadr or caddr recursively
1904 according to whether the symbol's value is non-nil or nil. */
1905 car
= XCONS (elt
)->car
;
1906 if (XTYPE (car
) == Lisp_Symbol
)
1908 tem
= Fboundp (car
);
1909 elt
= XCONS (elt
)->cdr
;
1910 if (XTYPE (elt
) != Lisp_Cons
)
1912 /* elt is now the cdr, and we know it is a cons cell.
1913 Use its car if CAR has a non-nil value. */
1916 tem
= Fsymbol_value (car
);
1918 { elt
= XCONS (elt
)->car
; goto tail_recurse
; }
1920 /* Symbol's value is nil (or symbol is unbound)
1921 Get the cddr of the original list
1922 and if possible find the caddr and use that. */
1923 elt
= XCONS (elt
)->cdr
;
1926 else if (XTYPE (elt
) != Lisp_Cons
)
1928 elt
= XCONS (elt
)->car
;
1931 else if (XTYPE (car
) == Lisp_Int
)
1933 register int lim
= XINT (car
);
1934 elt
= XCONS (elt
)->cdr
;
1936 /* Negative int means reduce maximum width.
1937 DO NOT change MINENDCOL here!
1938 (20 -10 . foo) should truncate foo to 10 col
1939 and then pad to 20. */
1940 maxendcol
= min (maxendcol
, hpos
- lim
);
1943 /* Padding specified. Don't let it be more than
1946 if (lim
> maxendcol
)
1948 /* If that's more padding than already wanted, queue it.
1949 But don't reduce padding already specified even if
1950 that is beyond the current truncation point. */
1951 if (lim
> minendcol
)
1956 else if (XTYPE (car
) == Lisp_String
|| XTYPE (car
) == Lisp_Cons
)
1958 register int limit
= 50;
1959 /* LIMIT is to protect against circular lists. */
1960 while (XTYPE (elt
) == Lisp_Cons
&& --limit
> 0
1961 && hpos
< maxendcol
)
1963 hpos
= display_mode_element (w
, vpos
, hpos
, depth
,
1966 elt
= XCONS (elt
)->cdr
;
1974 return (display_string (w
, vpos
, "*invalid*", hpos
, 0,
1975 minendcol
, maxendcol
));
1979 if (minendcol
> hpos
)
1980 hpos
= display_string (w
, vpos
, "", hpos
, 0, minendcol
, -1);
1984 /* Return a string for the output of a mode line %-spec for window W,
1985 generated by character C and width MAXWIDTH. */
1988 decode_mode_spec (w
, c
, maxwidth
)
1991 register int maxwidth
;
1993 Lisp_Object obj
= Qnil
;
1994 SCREEN_PTR scr
= XSCREEN (WINDOW_SCREEN (w
));
1995 char *decode_mode_spec_buf
= (char *) SCREEN_TEMP_GLYPHS (scr
)->total_contents
;
1997 if (maxwidth
> SCREEN_WIDTH (scr
))
1998 maxwidth
= SCREEN_WIDTH (scr
);
2003 obj
= current_buffer
->name
;
2005 if (maxwidth
>= 3 && XSTRING (obj
)->size
> maxwidth
)
2007 bcopy (XSTRING (obj
)->data
, decode_mode_spec_buf
, maxwidth
- 1);
2008 decode_mode_spec_buf
[maxwidth
- 1] = '\\';
2009 decode_mode_spec_buf
[maxwidth
] = '\0';
2010 return decode_mode_spec_buf
;
2016 obj
= current_buffer
->filename
;
2020 else if (XTYPE (obj
) == Lisp_String
&& XSTRING (obj
)->size
> maxwidth
)
2022 bcopy ("...", decode_mode_spec_buf
, 3);
2023 bcopy (XSTRING (obj
)->data
+ XSTRING (obj
)->size
- maxwidth
+ 3,
2024 decode_mode_spec_buf
+ 3, maxwidth
- 3);
2025 return decode_mode_spec_buf
;
2031 obj
= current_buffer
->mode_name
;
2035 if (BEGV
> BEG
|| ZV
< Z
)
2040 if (!NULL (current_buffer
->read_only
))
2042 if (MODIFF
> current_buffer
->save_modified
)
2047 /* status of process */
2049 obj
= Fget_buffer_process (Fcurrent_buffer ());
2051 return "no process";
2052 obj
= Fsymbol_name (Fprocess_status (obj
));
2055 return "no processes";
2056 #endif /* subprocesses */
2060 int pos
= marker_position (w
->start
);
2061 int total
= ZV
- BEGV
;
2063 if (XFASTINT (w
->window_end_pos
) <= Z
- ZV
)
2070 else if (pos
<= BEGV
)
2074 total
= ((pos
- BEGV
) * 100 + total
- 1) / total
;
2075 /* We can't normally display a 3-digit number,
2076 so get us a 2-digit number that is close. */
2079 sprintf (decode_mode_spec_buf
, "%2d%%", total
);
2080 return decode_mode_spec_buf
;
2092 if (command_loop_level
> 5)
2094 p
= decode_mode_spec_buf
;
2095 for (i
= 0; i
< command_loop_level
; i
++)
2098 return decode_mode_spec_buf
;
2106 if (command_loop_level
> 5)
2108 p
= decode_mode_spec_buf
;
2109 for (i
= 0; i
< command_loop_level
; i
++)
2112 return decode_mode_spec_buf
;
2117 static char lots_of_dashes
[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
2121 if (maxwidth
< sizeof (lots_of_dashes
))
2122 return lots_of_dashes
;
2125 for (p
= decode_mode_spec_buf
, i
= maxwidth
; i
> 0; i
--)
2129 return decode_mode_spec_buf
;
2133 if (XTYPE (obj
) == Lisp_String
)
2134 return (char *) XSTRING (obj
)->data
;
2139 /* Display STRING on one line of window W, starting at HPOS.
2140 Display at position VPOS. Caller should have done get_display_line.
2142 TRUNCATE is GLYPH to display at end if truncated. Zero for none.
2144 MINCOL is the first column ok to end at. (Pad with spaces to this col.)
2145 MAXCOL is the last column ok to end at. Truncate here.
2146 -1 for MINCOL or MAXCOL means no explicit minimum or maximum.
2147 Both count from the left edge of the screen, as does HPOS.
2148 The right edge of W is an implicit maximum.
2149 If TRUNCATE is nonzero, the implicit maximum is one column before the edge.
2151 Returns ending hpos */
2154 display_string (w
, vpos
, string
, hpos
, truncate
, mincol
, maxcol
)
2156 unsigned char *string
;
2163 int hscroll
= XINT (w
->hscroll
);
2164 int tab_width
= XINT (current_buffer
->tab_width
);
2165 register GLYPH
*start
;
2166 register GLYPH
*end
;
2167 struct screen_glyphs
*desired_glyphs
= SCREEN_DESIRED_GLYPHS (XSCREEN (w
->screen
));
2168 GLYPH
*p1start
= desired_glyphs
->glyphs
[vpos
] + hpos
;
2169 int window_width
= XFASTINT (w
->width
);
2171 /* Use the standard display table, not the window's display table.
2172 We don't want the mode line in rot13. */
2173 register struct Lisp_Vector
*dp
= 0;
2175 if (XTYPE (Vstandard_display_table
) == Lisp_Vector
2176 && XVECTOR (Vstandard_display_table
)->size
== DISP_TABLE_SIZE
)
2177 dp
= XVECTOR (Vstandard_display_table
);
2179 if (tab_width
<= 0 || tab_width
> 20) tab_width
= 8;
2182 start
= desired_glyphs
->glyphs
[vpos
] + XFASTINT (w
->left
);
2183 end
= start
+ window_width
- (truncate
!= 0);
2185 if ((window_width
+ XFASTINT (w
->left
))
2186 != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w
))))
2189 if (maxcol
>= 0 && end
- desired_glyphs
->glyphs
[vpos
] > maxcol
)
2190 end
= desired_glyphs
->glyphs
[vpos
] + maxcol
;
2191 if (maxcol
>= 0 && mincol
> maxcol
)
2198 if (c
>= 040 && c
< 0177
2199 && (dp
== 0 || XTYPE (DISP_CHAR_ROPE (dp
, c
)) != Lisp_String
))
2209 if (p1
>= start
&& p1
< end
)
2213 while ((p1
- start
+ hscroll
- (hscroll
> 0)) % tab_width
);
2215 else if (dp
!= 0 && XTYPE (DISP_CHAR_ROPE (dp
, c
)) == Lisp_String
)
2216 p1
= copy_rope (p1
, start
, DISP_CHAR_ROPE (dp
, c
));
2217 else if (c
< 0200 && buffer_defaults
.ctl_arrow
)
2220 *p1
= (dp
&& XTYPE (DISP_CTRL_GLYPH (dp
)) == Lisp_Int
2221 ? XINT (DISP_CTRL_GLYPH (dp
)) : '^');
2223 if (p1
>= start
&& p1
< end
)
2230 *p1
= (dp
&& XTYPE (DISP_ESCAPE_GLYPH (dp
)) == Lisp_Int
2231 ? XINT (DISP_ESCAPE_GLYPH (dp
)) : '\\');
2233 if (p1
>= start
&& p1
< end
)
2234 *p1
= (c
>> 6) + '0';
2236 if (p1
>= start
&& p1
< end
)
2237 *p1
= (7 & (c
>> 3)) + '0';
2239 if (p1
>= start
&& p1
< end
)
2240 *p1
= (7 & c
) + '0';
2248 if (truncate
) *p1
++ = truncate
;
2250 else if (mincol
>= 0)
2252 end
= desired_glyphs
->glyphs
[vpos
] + mincol
;
2258 register int len
= p1
- desired_glyphs
->glyphs
[vpos
];
2260 if (len
> desired_glyphs
->used
[vpos
])
2261 desired_glyphs
->used
[vpos
] = len
;
2262 desired_glyphs
->glyphs
[vpos
][desired_glyphs
->used
[vpos
]] = 0;
2271 staticpro (&last_arrow_position
);
2272 staticpro (&last_arrow_string
);
2273 last_arrow_position
= Qnil
;
2274 last_arrow_string
= Qnil
;
2276 DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string
,
2277 "String displayed by mode-line-format's \"%m\" specifiation.");
2278 Vglobal_mode_string
= Qnil
;
2280 DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position
,
2281 "Marker for where to display an arrow on top of the buffer text.\n\
2282 This must be the beginning of a line in order to work.\n\
2283 See also `overlay-arrow-string'.");
2284 Voverlay_arrow_position
= Qnil
;
2286 DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string
,
2287 "String to display as an arrow. See also `overlay-arrow-position'.");
2288 Voverlay_arrow_string
= Qnil
;
2290 DEFVAR_INT ("scroll-step", &scroll_step
,
2291 "*The number of lines to try scrolling a window by when point moves out.\n\
2292 If that fails to bring point back on screen, point is centered instead.\n\
2293 If this is zero, point is always centered after it moves off screen.");
2295 DEFVAR_INT ("debug-end-pos", &debug_end_pos
, "Don't ask");
2297 DEFVAR_BOOL ("truncate-partial-width-windows",
2298 &truncate_partial_width_windows
,
2299 "*Non-nil means truncate lines in all windows less than full screen wide.");
2300 truncate_partial_width_windows
= 1;
2302 DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video
,
2303 "*Non-nil means use inverse video for the mode line.");
2304 mode_line_inverse_video
= 1;
2306 #ifndef MULTI_SCREEN
2307 defsubr (&Sredraw_display
);
2308 #endif /* MULTI_SCREEN */
2311 /* initialize the window system */
2314 Lisp_Object root_window
;
2315 #ifndef COMPILER_REGISTER_BUG
2317 #endif /* COMPILER_REGISTER_BUG */
2318 struct window
*mini_w
;
2320 this_line_bufpos
= 0;
2322 mini_w
= XWINDOW (minibuf_window
);
2323 root_window
= mini_w
->prev
;
2325 echo_area_glyphs
= 0;
2326 previous_echo_glyphs
= 0;
2328 if (!noninteractive
)
2330 SCREEN_PTR s
= XSCREEN (WINDOW_SCREEN (XWINDOW (root_window
)));
2331 XFASTINT (XWINDOW (root_window
)->top
) = 0;
2332 set_window_height (root_window
, SCREEN_HEIGHT (s
) - 1, 0);
2333 XFASTINT (mini_w
->top
) = SCREEN_HEIGHT (s
) - 1;
2334 set_window_height (minibuf_window
, 1, 0);
2336 XFASTINT (XWINDOW (root_window
)->width
) = SCREEN_WIDTH (s
);
2337 XFASTINT (mini_w
->width
) = SCREEN_WIDTH (s
);