Initial revision
[bpt/emacs.git] / src / xdisp.c
CommitLineData
a2889657
JB
1/* Display generation from window structure and buffer text.
2 Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
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"
35
36extern int interrupt_input;
37extern int command_loop_level;
38
39/* Nonzero means print newline before next minibuffer message. */
40
41int noninteractive_need_newline;
42
43#define min(a, b) ((a) < (b) ? (a) : (b))
44#define max(a, b) ((a) > (b) ? (a) : (b))
45
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. */
49static int this_line_bufpos;
50
51/* Number of characters past the end of this line,
52 including the terminating newline */
53static int this_line_endpos;
54
55/* The vertical position of this screen line. */
56static int this_line_vpos;
57
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 */
61static int this_line_start_hpos;
62
63/* Buffer that this_line variables are describing. */
64static struct buffer *this_line_buffer;
65
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. */
69static int scroll_bottom_vpos;
70
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. */
75char *previous_echo_glyphs;
76
77/* Nonzero means truncate lines in all windows less wide than the screen */
78int truncate_partial_width_windows;
79
80Lisp_Object Vglobal_mode_string;
81
82/* Marker for where to display an arrow on top of the buffer text. */
83Lisp_Object Voverlay_arrow_position;
84
85/* String to display for the arrow. */
86Lisp_Object Voverlay_arrow_string;
87
88/* Values of those variables at last redisplay. */
89Lisp_Object last_arrow_position, last_arrow_string;
90
91/* Nonzero if overlay arrow has been displayed once in this window. */
92static int overlay_arrow_seen;
93
94/* If cursor motion alone moves point off screen,
95 Try scrolling this many lines up or down if that will bring it back. */
96int scroll_step;
97
98/* Nonzero if try_window_id has made blank lines at window bottom
99 since the last redisplay that paused */
100static int blank_end_of_window;
101
102/* Number of windows showing the buffer of the selected window.
103 keyboard.c refers to this. */
104int buffer_shared;
105
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. */
109
110static int cursor_vpos;
111static int cursor_hpos;
112
113int debug_end_pos;
114
115/* Nonzero means display mode line highlighted */
116int mode_line_inverse_video;
117
118static void echo_area_display ();
119void mark_window_display_accurate ();
120static void redisplay_windows ();
121static void redisplay_window ();
122static void try_window ();
123static int try_window_id ();
124static struct position *display_text_line ();
125static void display_mode_line ();
126static int display_mode_element ();
127static char *fmodetrunc ();
128static char *decode_mode_spec ();
129static int display_string ();
130
131/* Prompt to display in front of the minibuffer contents */
132char *minibuf_prompt;
133
134/* Width in columns of current minibuffer prompt. */
135int minibuf_prompt_width;
136
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. */
141char *echo_area_glyphs;
142
143/* true iff we should redraw the mode lines on the next redisplay */
144int update_mode_lines;
145
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. */
149int beg_unchanged;
150
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. */
154int end_unchanged;
155
156/* MODIFF as of last redisplay that finished;
157 if it matches MODIFF, beg_unchanged and end_unchanged
158 contain no useful information */
159int unchanged_modified;
160
161/* Nonzero if head_clip or tail_clip of current buffer has changed
162 since last redisplay that finished */
163int clip_changed;
164
165/* Nonzero if window sizes or contents have changed
166 since last redisplay that finished */
167int windows_or_buffers_changed;
168
169\f
170#ifndef MULTI_SCREEN
171
172DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "",
173 "Clear the screen and output again what is supposed to appear on it.")
174 ()
175{
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;
187}
188
189#endif /* not MULTI_SCREEN */
190\f
9c74a0dd 191/* Buffer used for messages formatted by `message'. */
a2889657
JB
192char *message_buf;
193
9c74a0dd
JB
194/* Nonzero if message_buf is being used by print;
195 zero if being used by message. */
196int message_buf_print;
197
a2889657
JB
198/* dump an informative message to the minibuf */
199/* VARARGS 1 */
200
201void
202message (m, a1, a2, a3)
203 char *m;
204{
205 if (noninteractive)
206 {
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);
213 }
214 else if (INTERACTIVE)
215 {
216#ifdef NO_ARG_ARRAY
217 int a[3];
218 a[0] = a1;
219 a[1] = a2;
220 a[2] = a3;
221
222 doprnt (SCREEN_MESSAGE_BUF (selected_screen),
223 SCREEN_WIDTH (selected_screen), m, 0, 3, a);
224#else
225 doprnt (SCREEN_MESSAGE_BUF (selected_screen),
226 SCREEN_WIDTH (selected_screen), m, 0, 3, &a1);
227#endif /* NO_ARG_ARRAY */
228
229 echo_area_glyphs = SCREEN_MESSAGE_BUF (selected_screen);
9c74a0dd
JB
230
231 /* Print should start at the beginning of the message
232 buffer next time. */
233 message_buf_print = 0;
234
a2889657
JB
235 do_pending_window_change ();
236 echo_area_display ();
237 update_screen (XSCREEN (XWINDOW (minibuf_window)->screen), 1, 1);
238 do_pending_window_change ();
239 }
240}
241
242/* Specify m, a string, as a message in the minibuf. */
243void
244message1 (m)
245 char *m;
246{
a2889657
JB
247 if (noninteractive)
248 {
249 if (noninteractive_need_newline)
250 putc ('\n', stderr);
251 noninteractive_need_newline = 0;
252 fprintf (stderr, "%s\n", m);
253 fflush (stderr);
254 }
255 else if (INTERACTIVE)
256 {
257 echo_area_glyphs = m;
258 do_pending_window_change ();
259 echo_area_display ();
260 update_screen (XSCREEN (XWINDOW (minibuf_window)->screen), 1, 1);
261 do_pending_window_change ();
262 }
263}
264
265static void
266echo_area_display ()
267{
268 register int vpos;
269 SCREEN_PTR s;
270
271#ifdef MULTI_SCREEN
272 choose_minibuf_screen ();
273 s = XSCREEN (XWINDOW (minibuf_window)->screen);
274
275 if (!s->visible)
276 return;
277#endif
278
279 if (screen_garbaged)
280 {
281 Fredraw_display ();
282 screen_garbaged = 0;
283 }
284
285 if (echo_area_glyphs || minibuf_level == 0)
286 {
287 vpos = XFASTINT (XWINDOW (minibuf_window)->top);
288 get_display_line (s, vpos, 0);
289 display_string (XWINDOW (minibuf_window), vpos,
290 echo_area_glyphs ? echo_area_glyphs : "",
291 0, 0, 0, SCREEN_WIDTH (s));
292
293 /* If desired cursor location is on this line, put it at end of text */
294 if (SCREEN_CURSOR_Y (s) == vpos)
295 SCREEN_CURSOR_X (s) = s->desired_glyphs->used[vpos];
296 }
297 else if (!EQ (minibuf_window, selected_window))
298 windows_or_buffers_changed++;
299
300 if (EQ (minibuf_window, selected_window))
301 this_line_bufpos = 0;
302
303 previous_echo_glyphs = echo_area_glyphs;
304}
305\f
306/* Do a screen update, taking possible shortcuts into account.
307 This is the main external entry point for redisplay.
308
309 If the last redisplay displayed an echo area message and that
310 message is no longer requested, we clear the echo area
311 or bring back the minibuffer if that is in use.
312
313 Everyone would like to have a hook here to call eval,
314 but that cannot be done safely without a lot of changes elsewhere.
315 This can be called from signal handlers; with alarms set up;
316 or with synchronous processes running.
317 See the function `echo' in keyboard.c.
318 See Fcall_process; if you called it from here, it could be
319 entered recursively. */
320
321void
322redisplay ()
323{
324 register struct window *w = XWINDOW (selected_window);
325 register int pause;
326 int must_finish = 0;
327 int all_windows;
328 register int tlbufpos, tlendpos;
329 struct position pos;
330 extern int input_pending;
331
332 if (noninteractive)
333 return;
334
335 /* Notice any pending interrupt request to change screen size. */
336 do_pending_window_change ();
337
338 if (screen_garbaged)
339 {
340 Fredraw_display ();
341 screen_garbaged = 0;
342 }
343
344 if (echo_area_glyphs || previous_echo_glyphs)
345 {
346 echo_area_display ();
347 must_finish = 1;
348 }
349
350 if (clip_changed || windows_or_buffers_changed)
351 update_mode_lines++;
352
353 /* Detect case that we need to write a star in the mode line. */
354 if (XFASTINT (w->last_modified) < MODIFF
355 && XFASTINT (w->last_modified) <= current_buffer->save_modified)
356 {
357 w->update_mode_line = Qt;
358 if (buffer_shared > 1)
359 update_mode_lines++;
360 }
361
362 SCREEN_SCROLL_BOTTOM_VPOS (XSCREEN (w->screen)) = -1;
363
364 all_windows = update_mode_lines || buffer_shared > 1;
365#ifdef MULTI_SCREEN
366 all_windows |= (XTYPE (Vglobal_minibuffer_screen) == Lisp_Screen
367 && selected_screen != XSCREEN (Vglobal_minibuffer_screen));
368#endif /* MULTI_SCREEN */
369
370 /* If specs for an arrow have changed, do thorough redisplay
371 to ensure we remove any arrow that should no longer exist. */
372 if (Voverlay_arrow_position != last_arrow_position
373 || Voverlay_arrow_string != last_arrow_string)
374 all_windows = 1, clip_changed = 1;
375
376 tlbufpos = this_line_bufpos;
377 tlendpos = this_line_endpos;
378 if (!all_windows && tlbufpos > 0 && NULL (w->update_mode_line)
379 && SCREEN_VISIBLE_P (XSCREEN (w->screen))
380 /* Make sure recorded data applies to current buffer, etc */
381 && this_line_buffer == current_buffer
382 && current_buffer == XBUFFER (w->buffer)
383 && NULL (w->force_start)
384 /* Point must be on the line that we have info recorded about */
385 && point >= tlbufpos
386 && point <= Z - tlendpos
387 /* All text outside that line, including its final newline,
388 must be unchanged */
389 && (XFASTINT (w->last_modified) >= MODIFF
390 || (beg_unchanged >= tlbufpos - 1
391 && GPT >= tlbufpos
392 && end_unchanged >= tlendpos
393 && Z - GPT >= tlendpos)))
394 {
395 if (tlbufpos > BEGV && FETCH_CHAR (tlbufpos - 1) != '\n'
396 && (tlbufpos == ZV
397 || FETCH_CHAR (tlbufpos) == '\n'))
398 /* Former continuation line has disappeared by becoming empty */
399 goto cancel;
400 else if (XFASTINT (w->last_modified) < MODIFF
401 || MINI_WINDOW_P (w))
402 {
403 cursor_vpos = -1;
404 overlay_arrow_seen = 0;
405 display_text_line (w, tlbufpos, this_line_vpos, this_line_start_hpos,
406 pos_tab_offset (w, tlbufpos));
407 /* If line contains point, is not continued,
408 and ends at same distance from eob as before, we win */
409 if (cursor_vpos >= 0 && this_line_bufpos
410 && this_line_endpos == tlendpos)
411 {
412 if (XFASTINT (w->width) != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w))))
413 preserve_other_columns (w);
414 goto update;
415 }
416 else
417 goto cancel;
418 }
419 else if (point == XFASTINT (w->last_point))
420 {
421 if (!must_finish)
422 {
423 do_pending_window_change ();
424 return;
425 }
426 goto update;
427 }
428 else
429 {
430 pos = *compute_motion (tlbufpos, 0,
431 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
432 point, 2, - (1 << (SHORTBITS - 1)),
433 XFASTINT (w->width) - 1
434 - (XFASTINT (w->width) + XFASTINT (w->left)
435 != SCREEN_WIDTH (selected_screen)),
436 XINT (w->hscroll), 0);
437 if (pos.vpos < 1)
438 {
439 SCREEN_CURSOR_X (selected_screen)
440 = XFASTINT (w->left) + max (pos.hpos, 0);
441 SCREEN_CURSOR_Y (selected_screen) = this_line_vpos;
442 goto update;
443 }
444 else
445 goto cancel;
446 }
447 cancel:
448 /* Text changed drastically or point moved off of line */
449 cancel_line (this_line_vpos, selected_screen);
450 }
451
452 this_line_bufpos = 0;
453 all_windows |= buffer_shared > 1;
454
455 if (all_windows)
456 {
457#ifdef MULTI_SCREEN
458 Lisp_Object tail;
459
460 /* Recompute # windows showing selected buffer.
461 This will be increment each time such a window is displayed. */
462 buffer_shared = 0;
463
464 for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr)
465 {
466 SCREEN_PTR s;
467
468 if (XTYPE (XCONS (tail)->car) != Lisp_Screen)
469 continue;
470
471 s = XSCREEN (XCONS (tail)->car);
472 if (s->visible)
473 {
474
475 /* Clear the echo area on screens where the minibuffer isn't. */
476 if (s != XSCREEN (XWINDOW (minibuf_window)->screen)
477 /* But only screens that have minibuffers. */
478 && s->has_minibuffer)
479 {
480 int vpos = XFASTINT (XWINDOW (s->minibuffer_window)->top);
481 register struct screen_glyphs *line;
482
483 get_display_line (s, vpos, 0);
484 display_string (XWINDOW (s->minibuffer_window), vpos, "",
485 0, 0, 0, s->width);
486 }
487
488 /* Redraw its windows. */
489 redisplay_windows (SCREEN_ROOT_WINDOW (s));
490 }
491 }
492#else
493 redisplay_windows (SCREEN_ROOT_WINDOW (s));
494#endif /* not MULTI_SCREEN */
495 }
496 else if (SCREEN_VISIBLE_P (selected_screen))
497 {
498 redisplay_window (selected_window, 1);
499 if (XFASTINT (w->width) != SCREEN_WIDTH (selected_screen))
500 preserve_other_columns (w);
501 }
502
503update:
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. */
507 if (interrupt_input)
508 unrequest_sigio ();
509 stop_polling ();
510
511#ifdef MULTI_SCREEN
512 if (all_windows)
513 {
514 Lisp_Object tail;
515
516 pause = 0;
517
518 for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr)
519 {
520 SCREEN_PTR s;
521
522 if (XTYPE (XCONS (tail)->car) != Lisp_Screen)
523 continue;
524
525 s = XSCREEN (XCONS (tail)->car);
526 if (s->visible)
527 {
528 pause |= update_screen (s, 0, 0, SCREEN_SCROLL_BOTTOM_VPOS (s));
529 if (!pause)
530 mark_window_display_accurate (s->root_window, 1);
531 }
532 }
533 }
534 else
535#endif /* MULTI_SCREEN */
536 if (SCREEN_VISIBLE_P (selected_screen))
537 pause = update_screen (selected_screen, 0, 0);
538
539 /* If screen does not match, prevent doing single-line-update next time.
540 Also, don't forget to check every line to update the arrow. */
541 if (pause)
542 {
543 this_line_bufpos = 0;
544 if (!NULL (last_arrow_position))
545 {
546 last_arrow_position = Qt;
547 last_arrow_string = Qt;
548 }
549 /* If we pause after scrolling, some lines in current_screen
550 may be null, so preserve_other_columns won't be able to
551 preserve all the vertical-bar separators. So, avoid using it
552 in that case. */
553 if (XFASTINT (w->width) != SCREEN_WIDTH (selected_screen))
554 update_mode_lines = 1;
555 }
556
557 /* Now text on screen agrees with windows, so
558 put info into the windows for partial redisplay to follow */
559
560 if (!pause)
561 {
562 register struct buffer *b = XBUFFER (w->buffer);
563
564 blank_end_of_window = 0;
565 clip_changed = 0;
566 unchanged_modified = BUF_MODIFF (b);
567 beg_unchanged = BUF_GPT (b) - BUF_BEG (b);
568 end_unchanged = BUF_Z (b) - BUF_GPT (b);
569
570 XFASTINT (w->last_point) = BUF_PT (b);
571 XFASTINT (w->last_point_x) = SCREEN_CURSOR_X (selected_screen);
572 XFASTINT (w->last_point_y) = SCREEN_CURSOR_Y (selected_screen);
573
574 if (all_windows)
575 mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 1);
576 else
577 {
578 w->update_mode_line = Qnil;
579 XFASTINT (w->last_modified) = BUF_MODIFF (b);
580 w->window_end_valid = Qt;
581 last_arrow_position = Voverlay_arrow_position;
582 last_arrow_string = Voverlay_arrow_string;
583 }
584 update_mode_lines = 0;
585 windows_or_buffers_changed = 0;
586 }
587
588 /* Start SIGIO interrupts coming again.
589 Having them off during the code above
590 makes it less likely one will discard output,
591 but not impossible, since there might be stuff
592 in the system buffer here.
593 But it is much hairier to try to do anything about that. */
594
595 if (interrupt_input)
596 request_sigio ();
597 start_polling ();
598
599 /* Change screen size now if a change is pending. */
600 do_pending_window_change ();
601}
602
603/* Redisplay, but leave alone any recent echo area message
604 unless another message has been requested in its place.
605
606 This is useful in situations where you need to redisplay but no
607 user action has occurred, making it inappropriate for the message
608 area to be cleared. See tracking_off and
609 wait_reading_process_input for examples of these situations. */
610
611redisplay_preserve_echo_area ()
612{
613 if (echo_area_glyphs == 0 && previous_echo_glyphs != 0)
614 {
615 echo_area_glyphs = previous_echo_glyphs;
616 redisplay ();
617 echo_area_glyphs = 0;
618 }
619 else
620 redisplay ();
621}
622
623void
624mark_window_display_accurate (window, flag)
625 Lisp_Object window;
626 int flag;
627{
628 register struct window *w;
629
630 for (;!NULL (window); window = w->next)
631 {
632 w = XWINDOW (window);
633
634 if (!NULL (w->buffer))
635 XFASTINT (w->last_modified)
636 = !flag ? 0
637 : XBUFFER (w->buffer) == current_buffer
638 ? MODIFF : BUF_MODIFF (XBUFFER (w->buffer));
639 w->window_end_valid = Qt;
640 w->update_mode_line = Qnil;
641
642 if (!NULL (w->vchild))
643 mark_window_display_accurate (w->vchild, flag);
644 if (!NULL (w->hchild))
645 mark_window_display_accurate (w->hchild, flag);
646 }
647
648 if (flag)
649 {
650 last_arrow_position = Voverlay_arrow_position;
651 last_arrow_string = Voverlay_arrow_string;
652 }
653 else
654 {
655 /* t is unequal to any useful value of Voverlay_arrow_... */
656 last_arrow_position = Qt;
657 last_arrow_string = Qt;
658 }
659}
660\f
661int do_id = 1;
662
663static void
664redisplay_windows (window)
665 Lisp_Object window;
666{
667 for (; !NULL (window); window = XWINDOW (window)->next)
668 redisplay_window (window, 0);
669}
670
671static void
672redisplay_window (window, just_this_one)
673 Lisp_Object window;
674 int just_this_one;
675{
676 register struct window *w = XWINDOW (window);
677 SCREEN_PTR s = XSCREEN (w->screen);
678 int height;
679 register int lpoint = point;
680 struct buffer *old = current_buffer;
681 register int width = XFASTINT (w->width) - 1
682 - (XFASTINT (w->width) + XFASTINT (w->left)
683 != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w))));
684 register int startp;
685 register int hscroll = XINT (w->hscroll);
686 struct position pos;
687 int opoint;
688 int tem;
689 int window_needs_modeline;
690
691 if (SCREEN_HEIGHT (s) == 0) abort (); /* Some bug zeros some core */
692
693 /* If this is a combination window, do its children; that's all. */
694
695 if (!NULL (w->vchild))
696 {
697 redisplay_windows (w->vchild);
698 return;
699 }
700 if (!NULL (w->hchild))
701 {
702 redisplay_windows (w->hchild);
703 return;
704 }
705 if (NULL (w->buffer))
706 abort ();
707
708 if (update_mode_lines)
709 w->update_mode_line = Qt;
710
711 /* Otherwise set up data on this window; select its buffer and point value */
712
713 height = window_internal_height (w);
714
715 if (MINI_WINDOW_P (w)
716 && (echo_area_glyphs
717 /* Don't display minibuffers except minibuf_window. */
718 || w != XWINDOW (minibuf_window)))
719 return;
720
721 current_buffer = XBUFFER (w->buffer);
722 opoint = point;
723
724 /* Count number of windows showing the selected buffer. */
725
726 if (!just_this_one
727 && current_buffer == XBUFFER (XWINDOW (selected_window)->buffer))
728 buffer_shared++;
729
730 /* POINT refers normally to the selected window.
731 For any other window, set up appropriate value. */
732
733 if (!EQ (window, selected_window))
734 {
735 SET_PT (marker_position (w->pointm));
736 if (point < BEGV)
737 {
738 point = BEGV;
739 Fset_marker (w->pointm, make_number (point), Qnil);
740 }
741 else if (point > (ZV - 1))
742 {
743 point = ZV;
744 Fset_marker (w->pointm, make_number (point), Qnil);
745 }
746 }
747
748 /* If window-start is screwed up, choose a new one. */
749
750 if (XMARKER (w->start)->buffer != current_buffer)
751 goto recenter;
752
753 startp = marker_position (w->start);
754
755 /* Handle case where place to start displaying has been specified */
756
757 if (!NULL (w->force_start))
758 {
759 w->update_mode_line = Qt;
760 w->force_start = Qnil;
761 XFASTINT (w->last_modified) = 0;
762 try_window (window, startp);
763 if (cursor_vpos < 0)
764 {
765 /* If point does not appear, move point so it does appear */
766 pos = *compute_motion (startp, 0,
767 ((EQ (window, minibuf_window) && startp == 1)
768 ? minibuf_prompt_width : 0)
769 +
770 (hscroll ? 1 - hscroll : 0),
771 ZV, height / 2,
772 - (1 << (SHORTBITS - 1)),
773 width, hscroll, pos_tab_offset (w, startp));
774 SET_PT (pos.bufpos);
775 if (w != XWINDOW (SCREEN_SELECTED_WINDOW (s)))
776 Fset_marker (w->pointm, make_number (point), Qnil);
777 else
778 {
779 lpoint = point;
780 SCREEN_CURSOR_X (s) = max (0, pos.hpos) + XFASTINT (w->left);
781 SCREEN_CURSOR_Y (s) = pos.vpos + XFASTINT (w->top);
782 }
783 }
784 goto done;
785 }
786
787 /* Handle case where text has not changed, only point,
788 and it has not moved off the screen */
789
790 /* This code is not used for minibuffer for the sake of
791 the case of redisplaying to replace an echo area message;
792 since in that case the minibuffer contents per se are usually unchanged.
793 This code is of no real use in the minibuffer since
794 the handling of this_line_bufpos, etc.,
795 in redisplay handles the same cases. */
796
797 if (XFASTINT (w->last_modified) >= MODIFF
798 && point >= startp && !clip_changed
799 && (just_this_one || XFASTINT (w->width) == SCREEN_WIDTH (s))
800 && !EQ (window, minibuf_window))
801 {
802 pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
803 point, height + 1, 10000, width, hscroll,
804 pos_tab_offset (w, startp));
805
806 if (pos.vpos < height)
807 {
808 /* Ok, point is still on screen */
809 if (w == XWINDOW (SCREEN_SELECTED_WINDOW (s)))
810 {
811 /* These variables are supposed to be origin 1 */
812 SCREEN_CURSOR_X (s) = max (0, pos.hpos) + XFASTINT (w->left);
813 SCREEN_CURSOR_Y (s) = pos.vpos + XFASTINT (w->top);
814 }
815 /* This doesn't do the trick, because if a window to the right of
816 this one must be redisplayed, this does nothing because there
817 is nothing in DesiredScreen yet, and then the other window is
818 redisplayed, making likes that are empty in this window's columns.
819 if (XFASTINT (w->width) != SCREEN_WIDTH (s))
820 preserve_my_columns (w);
821 */
822 goto done;
823 }
824 /* Don't bother trying redisplay with same start;
825 we already know it will lose */
826 }
827 /* If current starting point was originally the beginning of a line
828 but no longer is, find a new starting point. */
829 else if (!NULL (w->start_at_line_beg)
830 && !(startp == BEGV
831 || FETCH_CHAR (startp - 1) == '\n'))
832 {
833 goto recenter;
834 }
835 else if (just_this_one && !MINI_WINDOW_P (w)
836 && point >= startp
837 && XFASTINT (w->last_modified)
838 && ! EQ (w->window_end_valid, Qnil)
839 && do_id && !clip_changed
840 && !blank_end_of_window
841 && XFASTINT (w->width) == SCREEN_WIDTH (s)
842 && EQ (last_arrow_position, Voverlay_arrow_position)
843 && EQ (last_arrow_string, Voverlay_arrow_string)
844 && (tem = try_window_id (SCREEN_SELECTED_WINDOW (s)))
845 && tem != -2)
846 {
847 /* tem > 0 means success. tem == -1 means choose new start.
848 tem == -2 means try again with same start,
849 and nothing but whitespace follows the changed stuff.
850 tem == 0 means try again with same start. */
851 if (tem > 0)
852 goto done;
853 }
854 else if (startp >= BEGV && startp <= ZV
855 /* Avoid starting display at end of buffer! */
856 && (startp <= ZV || startp == BEGV
857 || (XFASTINT (w->last_modified) >= MODIFF)))
858 {
859 /* Try to redisplay starting at same place as before */
860 /* If point has not moved off screen, accept the results */
861 try_window (window, startp);
862 if (cursor_vpos >= 0)
863 goto done;
864 else
865 cancel_my_columns (w);
866 }
867
868 XFASTINT (w->last_modified) = 0;
869 w->update_mode_line = Qt;
870
871 /* Try to scroll by specified few lines */
872
873 if (scroll_step && !clip_changed)
874 {
875 if (point > startp)
876 {
877 pos = *vmotion (Z - XFASTINT (w->window_end_pos),
878 scroll_step, width, hscroll, window);
879 if (pos.vpos >= height)
880 goto scroll_fail;
881 }
882
883 pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step,
884 width, hscroll, window);
885
886 if (point >= pos.bufpos)
887 {
888 try_window (window, pos.bufpos);
889 if (cursor_vpos >= 0)
890 goto done;
891 else
892 cancel_my_columns (w);
893 }
894 scroll_fail: ;
895 }
896
897 /* Finally, just choose place to start which centers point */
898
899recenter:
900 pos = *vmotion (point, - height / 2, width, hscroll, window);
901 try_window (window, pos.bufpos);
902
903 startp = marker_position (w->start);
904 w->start_at_line_beg =
905 (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
906
907done:
908 /* If window not full width, must redo its mode line
909 if the window to its side is being redone */
910 if ((!NULL (w->update_mode_line)
911 || (!just_this_one && width < SCREEN_WIDTH (s) - 1))
912 && height != XFASTINT (w->height))
913 display_mode_line (w);
914
915 SET_PT (opoint);
916 current_buffer = old;
917 SET_PT (lpoint);
918}
919\f
920/* Do full redisplay on one window, starting at position `pos'. */
921
922static void
923try_window (window, pos)
924 Lisp_Object window;
925 register int pos;
926{
927 register struct window *w = XWINDOW (window);
928 register int height = window_internal_height (w);
929 register int vpos = XFASTINT (w->top);
930 register int last_text_vpos = vpos;
931 int tab_offset = pos_tab_offset (w, pos);
932 SCREEN_PTR s = XSCREEN (w->screen);
933 int width = XFASTINT (w->width) - 1
934 - (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s));
935 struct position val;
936
937 Fset_marker (w->start, make_number (pos), Qnil);
938 cursor_vpos = -1;
939 overlay_arrow_seen = 0;
940 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
941
942 while (--height >= 0)
943 {
944 val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
945 tab_offset += width;
946 if (val.vpos) tab_offset = 0;
947 vpos++;
948 if (pos != val.bufpos)
949 last_text_vpos
950 /* Next line, unless prev line ended in end of buffer with no cr */
951 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
952 pos = val.bufpos;
953 }
954
955 /* If last line is continued in middle of character,
956 include the split character in the text considered on the screen */
957 if (val.hpos < (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
958 pos++;
959
960 /* If bottom just moved off end of screen, change mode line percentage. */
961 if (XFASTINT (w->window_end_pos) == 0
962 && Z != pos)
963 w->update_mode_line = Qt;
964
965 /* Say where last char on screen will be, once redisplay is finished. */
966 XFASTINT (w->window_end_pos) = Z - pos;
967 XFASTINT (w->window_end_vpos) = last_text_vpos - XFASTINT (w->top);
968 /* But that is not valid info until redisplay finishes. */
969 w->window_end_valid = Qnil;
970}
971\f
972/* Try to redisplay when buffer is modified locally,
973 computing insert/delete line to preserve text outside
974 the bounds of the changes.
975 Return 1 if successful, 0 if if cannot tell what to do,
976 or -1 to tell caller to find a new window start,
977 or -2 to tell caller to do normal redisplay with same window start. */
978
979static int
980try_window_id (window)
981 Lisp_Object window;
982{
983 int pos;
984 register struct window *w = XWINDOW (window);
985 register int height = window_internal_height (w);
986 SCREEN_PTR s = XSCREEN (w->screen);
987 int top = XFASTINT (w->top);
988 int start = marker_position (w->start);
989 int width = XFASTINT (w->width) - 1
990 - (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s));
991 int hscroll = XINT (w->hscroll);
992 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
993 register int vpos;
994 register int i, tem;
995 int last_text_vpos = 0;
996 int stop_vpos;
997
998 struct position val, bp, ep, xp, pp;
999 int scroll_amount = 0;
1000 int delta;
1001 int tab_offset, epto;
1002
1003 if (GPT - BEG < beg_unchanged)
1004 beg_unchanged = GPT - BEG;
1005 if (Z - GPT < end_unchanged)
1006 end_unchanged = Z - GPT;
1007
1008 if (beg_unchanged + 1 < start)
1009 return 0; /* Give up if changes go above top of window */
1010
1011 /* Find position before which nothing is changed. */
1012 bp = *compute_motion (start, 0, lmargin,
1013 beg_unchanged + 1, 10000, 10000, width, hscroll,
1014 pos_tab_offset (w, start));
1015 if (bp.vpos >= height)
1016 return point < bp.bufpos && !bp.contin;
1017
1018 vpos = bp.vpos;
1019
1020 /* Find beginning of that screen line. Must display from there. */
1021 bp = *vmotion (bp.bufpos, 0, width, hscroll, window);
1022
1023 pos = bp.bufpos;
1024 val.hpos = lmargin;
1025 if (pos < start)
1026 return -1;
1027
1028 /* If about to start displaying at the beginning of a continuation line,
1029 really start with previous screen line, in case it was not
1030 continued when last redisplayed */
1031 if (bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0)
1032 {
1033 bp = *vmotion (bp.bufpos, -1, width, hscroll, window);
1034 --vpos;
1035 pos = bp.bufpos;
1036 }
1037
1038 if (bp.contin && bp.hpos != lmargin)
1039 {
1040 val.hpos = bp.prevhpos - width + lmargin;
1041 pos--;
1042 }
1043
1044 bp.vpos = vpos;
1045
1046 /* Find first visible newline after which no more is changed. */
1047 tem = find_next_newline (Z - max (end_unchanged, Z - ZV), 1);
1048 if (XTYPE (current_buffer->selective_display) == Lisp_Int
1049 && XINT (current_buffer->selective_display) > 0)
1050 while (tem < ZV - 1
1051 && (position_indentation (tem)
1052 >= XINT (current_buffer->selective_display)))
1053 tem = find_next_newline (tem, 1);
1054
1055 /* Compute the cursor position after that newline. */
1056 ep = *compute_motion (pos, vpos, val.hpos, tem,
1057 height, - (1 << (SHORTBITS - 1)),
1058 width, hscroll, pos_tab_offset (w, bp.bufpos));
1059
1060 /* If changes reach past the text available on the screen,
1061 just display rest of screen. */
1062 if (ep.bufpos > Z - XFASTINT (w->window_end_pos))
1063 stop_vpos = height;
1064 else
1065 stop_vpos = ep.vpos;
1066
1067 /* If no newline before ep, the line ep is on includes some changes
1068 that must be displayed. Make sure we don't stop before it. */
1069 /* Also, if changes reach all the way until ep.bufpos,
1070 it is possible that something was deleted after the
1071 newline before it, so the following line must be redrawn. */
1072 if (stop_vpos == ep.vpos
1073 && (ep.bufpos == BEGV
1074 || FETCH_CHAR (ep.bufpos - 1) != '\n'
1075 || ep.bufpos == Z - end_unchanged))
1076 stop_vpos = ep.vpos + 1;
1077
1078 cursor_vpos = -1;
1079 overlay_arrow_seen = 0;
1080
1081 /* If changes do not reach to bottom of window,
1082 figure out how much to scroll the rest of the window */
1083 if (stop_vpos < height)
1084 {
1085 /* Now determine how far up or down the rest of the window has moved */
1086 epto = pos_tab_offset (w, ep.bufpos);
1087 xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
1088 Z - XFASTINT (w->window_end_pos),
1089 10000, 0, width, hscroll, epto);
1090 scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
1091
1092 /* Is everything on screen below the changes whitespace?
1093 If so, no scrolling is really necessary. */
1094 for (i = ep.bufpos; i < xp.bufpos; i++)
1095 {
1096 tem = FETCH_CHAR (i);
1097 if (tem != ' ' && tem != '\n' && tem != '\t')
1098 break;
1099 }
1100 if (i == xp.bufpos)
1101 return -2;
1102
1103 XFASTINT (w->window_end_vpos) += scroll_amount;
1104
1105 /* Before doing any scrolling, verify that point will be on screen. */
1106 if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height))
1107 {
1108 if (point <= xp.bufpos)
1109 {
1110 pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
1111 point, height, - (1 << (SHORTBITS - 1)),
1112 width, hscroll, epto);
1113 }
1114 else
1115 {
1116 pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
1117 point, height, - (1 << (SHORTBITS - 1)),
1118 width, hscroll, pos_tab_offset (w, xp.bufpos));
1119 }
1120 if (pp.bufpos < point || pp.vpos == height)
1121 return 0;
1122 cursor_vpos = pp.vpos + top;
1123 cursor_hpos = pp.hpos + XFASTINT (w->left);
1124 }
1125
1126 if (stop_vpos - scroll_amount >= height
1127 || ep.bufpos == xp.bufpos)
1128 {
1129 if (scroll_amount < 0)
1130 stop_vpos -= scroll_amount;
1131 scroll_amount = 0;
1132 /* In this path, we have altered window_end_vpos
1133 and not left it negative.
1134 We must make sure that, in case display is preempted
1135 before the screen changes to reflect what we do here,
1136 further updates will not come to try_window_id
1137 and assume the screen and window_end_vpos match. */
1138 blank_end_of_window = 1;
1139 }
1140 else if (!scroll_amount)
1141 {}
1142 else if (bp.bufpos == Z - end_unchanged)
1143 {
1144 /* If reprinting everything is nearly as fast as scrolling,
1145 don't bother scrolling. Can happen if lines are short. */
1146 if (scroll_cost (s, bp.vpos + top - scroll_amount,
1147 top + height - max (0, scroll_amount),
1148 scroll_amount)
1149 > xp.bufpos - bp.bufpos - 20)
1150 /* Return "try normal display with same window-start."
1151 Too bad we can't prevent further scroll-thinking. */
1152 return -2;
1153 /* If pure deletion, scroll up as many lines as possible.
1154 In common case of killing a line, this can save the
1155 following line from being overwritten by scrolling
1156 and therefore having to be redrawn. */
1157 tem = scroll_screen_lines (s, bp.vpos + top - scroll_amount,
1158 top + height - max (0, scroll_amount),
1159 scroll_amount);
1160 if (!tem) stop_vpos = height;
1161 }
1162 else if (scroll_amount)
1163 {
1164 /* If reprinting everything is nearly as fast as scrolling,
1165 don't bother scrolling. Can happen if lines are short. */
1166 /* Note that if scroll_amount > 0, xp.bufpos - bp.bufpos is an
1167 overestimate of cost of reprinting, since xp.bufpos
1168 would end up below the bottom of the window. */
1169 if (scroll_cost (s, ep.vpos + top - scroll_amount,
1170 top + height - max (0, scroll_amount),
1171 scroll_amount)
1172 > xp.bufpos - ep.bufpos - 20)
1173 /* Return "try normal display with same window-start."
1174 Too bad we can't prevent further scroll-thinking. */
1175 return -2;
1176 tem = scroll_screen_lines (s, ep.vpos + top - scroll_amount,
1177 top + height - max (0, scroll_amount),
1178 scroll_amount);
1179 if (!tem) stop_vpos = height;
1180 }
1181 }
1182
1183 /* In any case, do not display past bottom of window */
1184 if (stop_vpos >= height)
1185 {
1186 stop_vpos = height;
1187 scroll_amount = 0;
1188 }
1189
1190 /* Handle case where pos is before w->start --
1191 can happen if part of line had been clipped and is not clipped now */
1192 if (vpos == 0 && pos < marker_position (w->start))
1193 Fset_marker (w->start, make_number (pos), Qnil);
1194
1195 /* Redisplay the lines where the text was changed */
1196 last_text_vpos = vpos;
1197 tab_offset = pos_tab_offset (w, pos);
1198 /* If we are starting display in mid-character, correct tab_offset
1199 to account for passing the line that that character really starts in. */
1200 if (val.hpos < lmargin)
1201 tab_offset += width;
1202 while (vpos < stop_vpos)
1203 {
1204 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
1205 tab_offset += width;
1206 if (val.vpos) tab_offset = 0;
1207 if (pos != val.bufpos)
1208 last_text_vpos
1209 /* Next line, unless prev line ended in end of buffer with no cr */
1210 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
1211 pos = val.bufpos;
1212 }
1213
1214 /* There are two cases:
1215 1) we have displayed down to the bottom of the window
1216 2) we have scrolled lines below stop_vpos by scroll_amount */
1217
1218 if (vpos == height)
1219 {
1220 /* If last line is continued in middle of character,
1221 include the split character in the text considered on the screen */
1222 if (val.hpos < lmargin)
1223 val.bufpos++;
1224 XFASTINT (w->window_end_vpos) = last_text_vpos;
1225 XFASTINT (w->window_end_pos) = Z - val.bufpos;
1226 }
1227
1228 /* If scrolling made blank lines at window bottom,
1229 redisplay to fill those lines */
1230 if (scroll_amount < 0)
1231 {
1232 /* Don't consider these lines for general-purpose scrolling.
1233 That will save time in the scrolling computation. */
1234 SCREEN_SCROLL_BOTTOM_VPOS (s) = xp.vpos;
1235 vpos = xp.vpos;
1236 pos = xp.bufpos;
1237 val.hpos = lmargin;
1238 if (pos == ZV)
1239 vpos = height + scroll_amount;
1240 else if (xp.contin && xp.hpos != lmargin)
1241 {
1242 val.hpos = xp.prevhpos - width + lmargin;
1243 pos--;
1244 }
1245
1246 blank_end_of_window = 1;
1247 tab_offset = pos_tab_offset (w, pos);
1248 /* If we are starting display in mid-character, correct tab_offset
1249 to account for passing the line that that character starts in. */
1250 if (val.hpos < lmargin)
1251 tab_offset += width;
1252
1253 while (vpos < height)
1254 {
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 pos = val.bufpos;
1259 }
1260
1261 /* Here is a case where display_text_line sets cursor_vpos wrong.
1262 Make it be fixed up, below. */
1263 if (xp.bufpos == ZV
1264 && xp.bufpos == point)
1265 cursor_vpos = -1;
1266 }
1267
1268 /* If bottom just moved off end of screen, change mode line percentage. */
1269 if (XFASTINT (w->window_end_pos) == 0
1270 && Z != val.bufpos)
1271 w->update_mode_line = Qt;
1272
1273 /* Attempt to adjust end-of-text positions to new bottom line */
1274 if (scroll_amount)
1275 {
1276 delta = height - xp.vpos;
1277 if (delta < 0
1278 || (delta > 0 && xp.bufpos <= ZV)
1279 || (delta == 0 && xp.hpos))
1280 {
1281 val = *vmotion (Z - XFASTINT (w->window_end_pos),
1282 delta, width, hscroll, window);
1283 XFASTINT (w->window_end_pos) = Z - val.bufpos;
1284 XFASTINT (w->window_end_vpos) += val.vpos;
1285 }
1286 }
1287
1288 w->window_end_valid = Qnil;
1289
1290 /* If point was not in a line that was displayed, find it */
1291 if (cursor_vpos < 0)
1292 {
1293 val = *compute_motion (start, 0, lmargin, point, 10000, 10000,
1294 width, hscroll, pos_tab_offset (w, start));
1295 /* Admit failure if point is off screen now */
1296 if (val.vpos >= height)
1297 {
1298 for (vpos = 0; vpos < height; vpos++)
1299 cancel_line (vpos + top, s);
1300 return 0;
1301 }
1302 cursor_vpos = val.vpos + top;
1303 cursor_hpos = val.hpos + XFASTINT (w->left);
1304 }
1305
1306 SCREEN_CURSOR_X (s) = max (0, cursor_hpos);
1307 SCREEN_CURSOR_Y (s) = cursor_vpos;
1308
1309 if (debug_end_pos)
1310 {
1311 val = *compute_motion (start, 0, lmargin, ZV,
1312 height, - (1 << (SHORTBITS - 1)),
1313 width, hscroll, pos_tab_offset (w, start));
1314 if (val.vpos != XFASTINT (w->window_end_vpos))
1315 abort ();
1316 if (XFASTINT (w->window_end_pos)
1317 != Z - val.bufpos)
1318 abort ();
1319 }
1320
1321 return 1;
1322}
1323\f
f7430cb6
JB
1324/* Copy glyphs from the rope FROM to T.
1325 But don't actually copy the parts that would come in before S.
a2889657
JB
1326 Value is T, advanced past the copied data.
1327
1328 Characters in FROM are grouped into units of `sizeof GLYPH' chars;
1329 any extra chars at the end of FROM are ignored. */
1330
1331GLYPH *
1332copy_rope (t, s, from)
1333 register GLYPH *t; /* Copy to here. */
1334 register GLYPH *s; /* Starting point. */
1335 Lisp_Object from; /* Data to copy; known to be a string. */
1336{
1337 register int n = XSTRING (from)->size / sizeof (GLYPH);
1338 register GLYPH *f = (GLYPH *) XSTRING (from)->data;
1339
1340 while (n--)
1341 {
1342 if (t >= s) *t = *f;
1343 ++t;
1344 ++f;
1345 }
1346 return t;
1347}
1348\f
1349/* Display one line of window w, starting at position START in W's buffer.
1350 Display starting at horizontal position HPOS, which is normally zero
1351 or negative. A negative value causes output up to hpos = 0 to be discarded.
1352 This is done for negative hscroll, or when this is a continuation line
1353 and the continuation occurred in the middle of a multi-column character.
1354
1355 TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
1356
1357 Display on position VPOS on the screen. (origin 0).
1358
1359 Returns a STRUCT POSITION giving character to start next line with
1360 and where to display it, including a zero or negative hpos.
1361 The vpos field is not really a vpos; it is 1 unless the line is continued */
1362
1363struct position val_display_text_line;
1364
1365static struct position *
1366display_text_line (w, start, vpos, hpos, taboffset)
1367 struct window *w;
1368 int start;
1369 int vpos;
1370 int hpos;
1371 int taboffset;
1372{
1373 register int pos = start;
1374 register int c;
1375 register GLYPH *p1;
1376 int end;
1377 register int pause;
1378 register unsigned char *p;
1379 GLYPH *endp;
1380 register GLYPH *startp;
1381 register GLYPH *p1prev;
1382 SCREEN_PTR s = XSCREEN (w->screen);
1383 int tab_width = XINT (current_buffer->tab_width);
1384 int ctl_arrow = !NULL (current_buffer->ctl_arrow);
1385 int width = XFASTINT (w->width) - 1
1386 - (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s));
1387 struct position val;
1388 int lastpos;
1389 int invis;
1390 int hscroll = XINT (w->hscroll);
1391 int truncate = hscroll
1392 || (truncate_partial_width_windows
1393 && XFASTINT (w->width) < SCREEN_WIDTH (s))
1394 || !NULL (current_buffer->truncate_lines);
1395 int selective
1396 = XTYPE (current_buffer->selective_display) == Lisp_Int
1397 ? XINT (current_buffer->selective_display)
1398 : !NULL (current_buffer->selective_display) ? -1 : 0;
1399#ifndef old
1400 int selective_e = selective && !NULL (current_buffer->selective_display_ellipses);
1401#endif
1402 register struct screen_glyphs *desired_glyphs = SCREEN_DESIRED_GLYPHS (s);
1403 register struct Lisp_Vector *dp = window_display_table (w);
1404 int selective_rlen
1405 = (selective && dp && XTYPE (DISP_INVIS_ROPE (dp)) == Lisp_String
1406 ? XSTRING (DISP_INVIS_ROPE (dp))->size / sizeof (GLYPH) : 0);
1407 GLYPH truncator = (dp == 0 || XTYPE (DISP_TRUNC_GLYPH (dp)) != Lisp_Int
1408 ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
1409 GLYPH continuer = (dp == 0 || XTYPE (DISP_CONTINUE_GLYPH (dp)) != Lisp_Int
1410 ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
1411
1412 hpos += XFASTINT (w->left);
1413 get_display_line (s, vpos, XFASTINT (w->left));
1414 if (tab_width <= 0 || tab_width > 20) tab_width = 8;
1415
1416 if (MINI_WINDOW_P (w) && start == 1
1417 && vpos == XFASTINT (w->top))
1418 {
1419 if (minibuf_prompt)
1420 hpos = display_string (w, vpos, minibuf_prompt, hpos,
1421 (!truncate ? continuer : truncator),
1422 -1, -1);
1423 minibuf_prompt_width = hpos;
1424 }
1425
1426 desired_glyphs->bufp[vpos] = pos;
1427 p1 = desired_glyphs->glyphs[vpos] + hpos;
1428 end = ZV;
1429 startp = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
1430 endp = startp + width;
1431
1432 /* Loop generating characters.
1433 Stop at end of buffer, before newline,
1434 or if reach or pass continuation column. */
1435
1436 pause = pos;
1437 while (p1 < endp)
1438 {
1439 p1prev = p1;
1440 if (pos == pause)
1441 {
1442 if (pos == end)
1443 break;
1444 if (pos == point && cursor_vpos < 0)
1445 {
1446 cursor_vpos = vpos;
1447 cursor_hpos = p1 - startp;
1448 }
1449
1450 pause = end;
1451 if (pos < point && point < pause)
1452 pause = point;
1453 if (pos < GPT && GPT < pause)
1454 pause = GPT;
1455
1456 p = &FETCH_CHAR (pos);
1457 }
1458 c = *p++;
1459 if (c >= 040 && c < 0177
1460 && (dp == 0 || XTYPE (DISP_CHAR_ROPE (dp, c)) != Lisp_String))
1461 {
1462 if (p1 >= startp)
1463 *p1 = c;
1464 p1++;
1465 }
1466 else if (c == '\n')
1467 {
1468 invis = 0;
1469 while (pos < end
1470 && selective > 0
1471 && position_indentation (pos + 1) >= selective)
1472 {
1473 invis = 1;
1474 pos = find_next_newline (pos + 1, 1);
1475 if (FETCH_CHAR (pos - 1) == '\n')
1476 pos--;
1477 }
1478 if (invis && selective_rlen > 0 && p1 >= startp)
1479 {
1480 p1 += selective_rlen;
1481 if (p1 - startp > width)
1482 p1 = endp;
1483 bcopy (XSTRING (DISP_INVIS_ROPE (dp))->data, p1prev,
1484 (p1 - p1prev) * sizeof (GLYPH));
1485 }
1486 break;
1487 }
1488 else if (c == '\t')
1489 {
1490 do
1491 {
1492 if (p1 >= startp && p1 < endp)
1493 *p1 = SPACEGLYPH;
1494 p1++;
1495 }
1496 while ((p1 - startp + taboffset + hscroll - (hscroll > 0))
1497 % tab_width);
1498 }
1499 else if (c == Ctl('M') && selective == -1)
1500 {
1501 pos = find_next_newline (pos, 1);
1502 if (FETCH_CHAR (pos - 1) == '\n')
1503 pos--;
1504 if (selective_rlen > 0)
1505 {
1506 p1 += selective_rlen;
1507 if (p1 - startp > width)
1508 p1 = endp;
1509 bcopy (XSTRING (DISP_INVIS_ROPE (dp))->data, p1prev,
1510 (p1 - p1prev) * sizeof (GLYPH));
1511 }
1512 break;
1513 }
1514 else if (dp != 0 && XTYPE (DISP_CHAR_ROPE (dp, c)) == Lisp_String)
1515 {
1516 p1 = copy_rope (p1, startp, DISP_CHAR_ROPE (dp, c));
1517 }
1518 else if (c < 0200 && ctl_arrow)
1519 {
1520 if (p1 >= startp)
1521 *p1 = (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
1522 ? XINT (DISP_CTRL_GLYPH (dp)) : '^');
1523 p1++;
1524 if (p1 >= startp)
1525 *p1 = c ^ 0100;
1526 p1++;
1527 }
1528 else
1529 {
1530 if (p1 >= startp)
1531 *p1 = (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
1532 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\');
1533 p1++;
1534 if (p1 >= startp)
1535 *p1 = (c >> 6) + '0';
1536 p1++;
1537 if (p1 >= startp)
1538 *p1 = (7 & (c >> 3)) + '0';
1539 p1++;
1540 if (p1 >= startp)
1541 *p1 = (7 & c) + '0';
1542 p1++;
1543 }
1544 pos++;
1545 }
1546
1547 val.hpos = - XINT (w->hscroll);
1548 if (val.hpos)
1549 val.hpos++;
1550
1551 val.vpos = 1;
1552
1553 lastpos = pos;
1554
1555 /* Handle continuation in middle of a character */
1556 /* by backing up over it */
1557 if (p1 > endp)
1558 {
1559 /* Start the next line with that same character */
1560 pos--;
1561 /* but at a negative hpos, to skip the columns output on this line. */
1562 val.hpos += p1prev - endp;
1563 /* Keep in this line everything up to the continuation column. */
1564 p1 = endp;
1565 }
1566
1567 /* Finish deciding which character to start the next line on,
1568 and what hpos to start it at.
1569 Also set `lastpos' to the last position which counts as "on this line"
1570 for cursor-positioning. */
1571
1572 if (pos < ZV)
1573 {
1574 if (FETCH_CHAR (pos) == '\n')
1575 /* If stopped due to a newline, start next line after it */
1576 pos++;
1577 else
1578 /* Stopped due to right margin of window */
1579 {
1580 if (truncate)
1581 {
1582 *p1++ = truncator;
1583 /* Truncating => start next line after next newline,
1584 and point is on this line if it is before the newline,
1585 and skip none of first char of next line */
1586 pos = find_next_newline (pos, 1);
1587 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
1588
1589 lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
1590 }
1591 else
1592 {
1593 *p1++ = continuer;
1594 val.vpos = 0;
1595 lastpos--;
1596 }
1597 }
1598 }
1599
1600 /* If point is at eol or in invisible text at eol,
1601 record its screen location now. */
1602
1603 if (start <= point && point <= lastpos && cursor_vpos < 0)
1604 {
1605 cursor_vpos = vpos;
1606 cursor_hpos = p1 - startp;
1607 }
1608
1609 if (cursor_vpos == vpos)
1610 {
1611 if (cursor_hpos < 0) cursor_hpos = 0;
1612 if (cursor_hpos > width) cursor_hpos = width;
1613 cursor_hpos += XFASTINT (w->left);
1614 if (w == XWINDOW (SCREEN_SELECTED_WINDOW (s)))
1615 {
1616 SCREEN_CURSOR_Y (s) = cursor_vpos;
1617 SCREEN_CURSOR_X (s) = cursor_hpos;
1618
1619 if (w == XWINDOW (selected_window))
1620 {
1621 /* Line is not continued and did not start
1622 in middle of character */
1623 if ((hpos - XFASTINT (w->left)
1624 == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
1625 && val.vpos)
1626 {
1627 this_line_bufpos = start;
1628 this_line_buffer = current_buffer;
1629 this_line_vpos = cursor_vpos;
1630 this_line_start_hpos = hpos;
1631 this_line_endpos = Z - lastpos;
1632 }
1633 else
1634 this_line_bufpos = 0;
1635 }
1636 }
1637 }
1638
1639 /* If hscroll and line not empty, insert truncation-at-left marker */
1640 if (hscroll && lastpos != start)
1641 {
1642 *startp = truncator;
1643 if (p1 <= startp)
1644 p1 = startp + 1;
1645 }
1646
1647 if (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s))
1648 {
1649 endp++;
1650 if (p1 < startp) p1 = startp;
1651 while (p1 < endp) *p1++ = SPACEGLYPH;
1652 *p1++ = '|';
1653 }
1654 desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
1655 p1 - desired_glyphs->glyphs[vpos]);
1656 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
1657
1658 /* If the start of this line is the overlay arrow-position,
1659 then put the arrow string into the display-line. */
1660
1661 if (XTYPE (Voverlay_arrow_position) == Lisp_Marker
1662 && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
1663 && start == marker_position (Voverlay_arrow_position)
1664 && XTYPE (Voverlay_arrow_string) == Lisp_String
1665 && ! overlay_arrow_seen)
1666 {
1667 unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
1668 int i;
1669 int len = XSTRING (Voverlay_arrow_string)->size;
1670
1671 if (len > XFASTINT (w->width) - 1)
1672 len = XFASTINT (w->width) - 1;
1673 for (i = 0; i < len; i++)
1674 startp[i] = p[i];
1675 if (desired_glyphs->used[vpos] <
1676 (len + startp - desired_glyphs->glyphs[vpos]))
1677 desired_glyphs->used[vpos] = len + startp - desired_glyphs->glyphs[vpos];
1678
1679 overlay_arrow_seen = 1;
1680 }
1681
1682 val.bufpos = pos;
1683 val_display_text_line = val;
1684 return &val_display_text_line;
1685}
1686\f
1687/* Display the mode line for window w */
1688
1689static void
1690display_mode_line (w)
1691 struct window *w;
1692{
1693 register int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
1694 register int left = XFASTINT (w->left);
1695 register int right = XFASTINT (w->width) + left;
1696 register SCREEN_PTR s = XSCREEN (WINDOW_SCREEN (w));
1697
1698 get_display_line (s, vpos, left);
1699 display_mode_element (w, vpos, left, 0, right, right,
1700 current_buffer->mode_line_format);
1701 SCREEN_DESIRED_GLYPHS (s)->bufp[vpos] = 0;
1702
1703 /* Make the mode line inverse video if the entire line
1704 is made of mode lines.
1705 I.e. if this window is full width,
1706 or if it is the child of a full width window
1707 (which implies that that window is split side-by-side
1708 and the rest of this line is mode lines of the sibling windows). */
1709 if (XFASTINT (w->width) == SCREEN_WIDTH (s)
1710 || XFASTINT (XWINDOW (w->parent)->width) == SCREEN_WIDTH (s))
1711 s->desired_glyphs->highlight[vpos] = mode_line_inverse_video;
1712
1713#ifdef HAVE_X_WINDOWS
1714 /* I'm trying this out because I saw Unimpress use it, but it's
1715 possible that this may fuck adversely with some window managers. jla */
1716
1717 if (SCREEN_IS_X (s)
1718 && (XTYPE (Vglobal_minibuffer_screen) != Lisp_Screen
1719 || s != XSCREEN (Vglobal_minibuffer_screen))
1720 && w == XWINDOW (s->selected_window)
1721 && (NULL (Fstring_equal (XBUFFER (w->buffer)->name, s->name))))
1722 x_set_name (s, XBUFFER (w->buffer)->name, Qnil);
1723#endif
1724}
1725
1726/* Contribute ELT to the mode line for window W.
1727 How it translates into text depends on its data type.
1728
1729 VPOS is the position of the mode line being displayed.
1730
1731 HPOS is the position (absolute on screen) where this element's text
1732 should start. The output is truncated automatically at the right
1733 edge of window W.
1734
1735 DEPTH is the depth in recursion. It is used to prevent
1736 infinite recursion here.
1737
1738 MINENDCOL is the hpos before which the element may not end.
1739 The element is padded at the right with spaces if nec
1740 to reach this column.
1741
1742 MAXENDCOL is the hpos past which this element may not extend.
1743 If MINENDCOL is > MAXENDCOL, MINENDCOL takes priority.
1744 (This is necessary to make nested padding and truncation work.)
1745
1746 Returns the hpos of the end of the text generated by ELT.
1747 The next element will receive that value as its HPOS arg,
1748 so as to concatenate the elements. */
1749
1750static int
1751display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
1752 struct window *w;
1753 register int vpos, hpos;
1754 int depth;
1755 int minendcol;
1756 register int maxendcol;
1757 register Lisp_Object elt;
1758{
1759 tail_recurse:
1760 if (depth > 10)
1761 goto invalid;
1762
1763 depth++;
1764
1765#ifdef SWITCH_ENUM_BUG
1766 switch ((int) XTYPE (elt))
1767#else
1768 switch (XTYPE (elt))
1769#endif
1770 {
1771 case Lisp_String:
1772 {
1773 /* A string: output it and check for %-constructs within it. */
1774 register unsigned char c;
1775 register unsigned char *this = XSTRING (elt)->data;
1776
1777 while (hpos < maxendcol && *this)
1778 {
1779 unsigned char *last = this;
1780 while ((c = *this++) != '\0' && c != '%')
1781 ;
1782 if (this - 1 != last)
1783 {
1784 register int lim = --this - last + hpos;
1785 hpos = display_string (w, vpos, last, hpos, 0, hpos,
1786 min (lim, maxendcol));
1787 }
1788 else /* c == '%' */
1789 {
1790 register int spec_width = 0;
1791
1792 /* We can't allow -ve args due to the "%-" construct */
1793 /* Argument specifies minwidth but not maxwidth
1794 (maxwidth can be specified by
1795 (<negative-number> . <stuff>) mode-line elements) */
1796
1797 while ((c = *this++) >= '0' && c <= '9')
1798 {
1799 spec_width = spec_width * 10 + (c - '0');
1800 }
1801
1802 spec_width += hpos;
1803 if (spec_width > maxendcol)
1804 spec_width = maxendcol;
1805
1806 if (c == 'M')
1807 hpos = display_mode_element (w, vpos, hpos, depth,
1808 spec_width, maxendcol,
1809 Vglobal_mode_string);
1810 else if (c != 0)
1811 hpos = display_string (w, vpos,
1812 decode_mode_spec (w, c,
1813 maxendcol - hpos),
1814 hpos, 0, spec_width, maxendcol);
1815 }
1816 }
1817 }
1818 break;
1819
1820 case Lisp_Symbol:
1821 /* A symbol: process the value of the symbol recursively
1822 as if it appeared here directly. Avoid error if symbol void.
1823 Special case: if value of symbol is a string, output the string
1824 literally. */
1825 {
1826 register Lisp_Object tem;
1827 tem = Fboundp (elt);
1828 if (!NULL (tem))
1829 {
1830 tem = Fsymbol_value (elt);
1831 /* If value is a string, output that string literally:
1832 don't check for % within it. */
1833 if (XTYPE (tem) == Lisp_String)
1834 hpos = display_string (w, vpos, XSTRING (tem)->data,
1835 hpos, 0, minendcol, maxendcol);
1836 /* Give up right away for nil or t. */
1837 else if (!EQ (tem, elt))
1838 { elt = tem; goto tail_recurse; }
1839 }
1840 }
1841 break;
1842
1843 case Lisp_Cons:
1844 {
1845 register Lisp_Object car, tem;
1846
1847 /* A cons cell: three distinct cases.
1848 If first element is a string or a cons, process all the elements
1849 and effectively concatenate them.
1850 If first element is a negative number, truncate displaying cdr to
1851 at most that many characters. If positive, pad (with spaces)
1852 to at least that many characters.
1853 If first element is a symbol, process the cadr or caddr recursively
1854 according to whether the symbol's value is non-nil or nil. */
1855 car = XCONS (elt)->car;
1856 if (XTYPE (car) == Lisp_Symbol)
1857 {
1858 tem = Fboundp (car);
1859 elt = XCONS (elt)->cdr;
1860 if (XTYPE (elt) != Lisp_Cons)
1861 goto invalid;
1862 /* elt is now the cdr, and we know it is a cons cell.
1863 Use its car if CAR has a non-nil value. */
1864 if (!NULL (tem))
1865 {
1866 tem = Fsymbol_value (car);
1867 if (!NULL (tem))
1868 { elt = XCONS (elt)->car; goto tail_recurse; }
1869 }
1870 /* Symbol's value is nil (or symbol is unbound)
1871 Get the cddr of the original list
1872 and if possible find the caddr and use that. */
1873 elt = XCONS (elt)->cdr;
1874 if (NULL (elt))
1875 break;
1876 else if (XTYPE (elt) != Lisp_Cons)
1877 goto invalid;
1878 elt = XCONS (elt)->car;
1879 goto tail_recurse;
1880 }
1881 else if (XTYPE (car) == Lisp_Int)
1882 {
1883 register int lim = XINT (car);
1884 elt = XCONS (elt)->cdr;
1885 if (lim < 0)
1886 /* Negative int means reduce maximum width.
1887 DO NOT change MINENDCOL here!
1888 (20 -10 . foo) should truncate foo to 10 col
1889 and then pad to 20. */
1890 maxendcol = min (maxendcol, hpos - lim);
1891 else if (lim > 0)
1892 {
1893 /* Padding specified. Don't let it be more than
1894 current maximum. */
1895 lim += hpos;
1896 if (lim > maxendcol)
1897 lim = maxendcol;
1898 /* If that's more padding than already wanted, queue it.
1899 But don't reduce padding already specified even if
1900 that is beyond the current truncation point. */
1901 if (lim > minendcol)
1902 minendcol = lim;
1903 }
1904 goto tail_recurse;
1905 }
1906 else if (XTYPE (car) == Lisp_String || XTYPE (car) == Lisp_Cons)
1907 {
1908 register int limit = 50;
1909 /* LIMIT is to protect against circular lists. */
1910 while (XTYPE (elt) == Lisp_Cons && --limit > 0
1911 && hpos < maxendcol)
1912 {
1913 hpos = display_mode_element (w, vpos, hpos, depth,
1914 hpos, maxendcol,
1915 XCONS (elt)->car);
1916 elt = XCONS (elt)->cdr;
1917 }
1918 }
1919 }
1920 break;
1921
1922 default:
1923 invalid:
1924 return (display_string (w, vpos, "*invalid*", hpos, 0,
1925 minendcol, maxendcol));
1926 }
1927
1928 end:
1929 if (minendcol > hpos)
1930 hpos = display_string (w, vpos, "", hpos, 0, minendcol, -1);
1931 return hpos;
1932}
1933\f
1934/* Return a string for the output of a mode line %-spec for window W,
1935 generated by character C and width MAXWIDTH. */
1936
1937static char *
1938decode_mode_spec (w, c, maxwidth)
1939 struct window *w;
1940 register char c;
1941 register int maxwidth;
1942{
1943 Lisp_Object obj = Qnil;
1944 SCREEN_PTR scr = XSCREEN (WINDOW_SCREEN (w));
1945 char *decode_mode_spec_buf = (char *) SCREEN_TEMP_GLYPHS (scr)->total_contents;
1946
1947 if (maxwidth > SCREEN_WIDTH (scr))
1948 maxwidth = SCREEN_WIDTH (scr);
1949
1950 switch (c)
1951 {
1952 case 'b':
1953 obj = current_buffer->name;
1954#if 0
1955 if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
1956 {
1957 bcopy (XSTRING (obj)->data, decode_mode_spec_buf, maxwidth - 1);
1958 decode_mode_spec_buf[maxwidth - 1] = '\\';
1959 decode_mode_spec_buf[maxwidth] = '\0';
1960 return decode_mode_spec_buf;
1961 }
1962#endif
1963 break;
1964
1965 case 'f':
1966 obj = current_buffer->filename;
1967#if 0
1968 if (NULL (obj))
1969 return "[none]";
1970 else if (XTYPE (obj) == Lisp_String && XSTRING (obj)->size > maxwidth)
1971 {
1972 bcopy ("...", decode_mode_spec_buf, 3);
1973 bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
1974 decode_mode_spec_buf + 3, maxwidth - 3);
1975 return decode_mode_spec_buf;
1976 }
1977#endif
1978 break;
1979
1980 case 'm':
1981 obj = current_buffer->mode_name;
1982 break;
1983
1984 case 'n':
1985 if (BEGV > BEG || ZV < Z)
1986 return " Narrow";
1987 break;
1988
1989 case '*':
1990 if (!NULL (current_buffer->read_only))
1991 return "%";
1992 if (MODIFF > current_buffer->save_modified)
1993 return "*";
1994 return "-";
1995
1996 case 's':
1997 /* status of process */
1998#ifdef subprocesses
1999 obj = Fget_buffer_process (Fcurrent_buffer ());
2000 if (NULL (obj))
2001 return "no process";
2002 obj = Fsymbol_name (Fprocess_status (obj));
2003 break;
2004#else
2005 return "no processes";
2006#endif /* subprocesses */
2007
2008 case 'p':
2009 {
2010 int pos = marker_position (w->start);
2011 int total = ZV - BEGV;
2012
2013 if (XFASTINT (w->window_end_pos) <= Z - ZV)
2014 {
2015 if (pos <= BEGV)
2016 return "All";
2017 else
2018 return "Bottom";
2019 }
2020 else if (pos <= BEGV)
2021 return "Top";
2022 else
2023 {
2024 total = ((pos - BEGV) * 100 + total - 1) / total;
2025 /* We can't normally display a 3-digit number,
2026 so get us a 2-digit number that is close. */
2027 if (total == 100)
2028 total = 99;
2029 sprintf (decode_mode_spec_buf, "%2d%%", total);
2030 return decode_mode_spec_buf;
2031 }
2032 }
2033
2034 case '%':
2035 return "%";
2036
2037 case '[':
2038 {
2039 int i;
2040 char *p;
2041
2042 if (command_loop_level > 5)
2043 return "[[[... ";
2044 p = decode_mode_spec_buf;
2045 for (i = 0; i < command_loop_level; i++)
2046 *p++ = '[';
2047 *p = 0;
2048 return decode_mode_spec_buf;
2049 }
2050
2051 case ']':
2052 {
2053 int i;
2054 char *p;
2055
2056 if (command_loop_level > 5)
2057 return " ...]]]";
2058 p = decode_mode_spec_buf;
2059 for (i = 0; i < command_loop_level; i++)
2060 *p++ = ']';
2061 *p = 0;
2062 return decode_mode_spec_buf;
2063 }
2064
2065 case '-':
2066 {
2067 static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
2068 register char *p;
2069 register int i;
2070
2071 if (maxwidth < sizeof (lots_of_dashes))
2072 return lots_of_dashes;
2073 else
2074 {
2075 for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
2076 *p++ = '-';
2077 *p = '\0';
2078 }
2079 return decode_mode_spec_buf;
2080 }
2081 }
2082
2083 if (XTYPE (obj) == Lisp_String)
2084 return (char *) XSTRING (obj)->data;
2085 else
2086 return "";
2087}
2088\f
2089/* Display STRING on one line of window W, starting at HPOS.
2090 Display at position VPOS. Caller should have done get_display_line.
2091
2092 TRUNCATE is GLYPH to display at end if truncated. Zero for none.
2093
2094 MINCOL is the first column ok to end at. (Pad with spaces to this col.)
2095 MAXCOL is the last column ok to end at. Truncate here.
2096 -1 for MINCOL or MAXCOL means no explicit minimum or maximum.
2097 Both count from the left edge of the screen, as does HPOS.
2098 The right edge of W is an implicit maximum.
2099 If TRUNCATE is nonzero, the implicit maximum is one column before the edge.
2100
2101 Returns ending hpos */
2102
2103static int
2104display_string (w, vpos, string, hpos, truncate, mincol, maxcol)
2105 struct window *w;
2106 unsigned char *string;
2107 int vpos, hpos;
2108 GLYPH truncate;
2109 int mincol, maxcol;
2110{
2111 register int c;
2112 register GLYPH *p1;
2113 int hscroll = XINT (w->hscroll);
2114 int tab_width = XINT (current_buffer->tab_width);
2115 register GLYPH *start;
2116 register GLYPH *end;
2117 struct screen_glyphs *desired_glyphs = SCREEN_DESIRED_GLYPHS (XSCREEN (w->screen));
2118 GLYPH *p1start = desired_glyphs->glyphs[vpos] + hpos;
2119 int window_width = XFASTINT (w->width);
2120
2121 /* Use the standard display table, not the window's display table.
2122 We don't want the mode line in rot13. */
2123 register struct Lisp_Vector *dp = 0;
2124
2125 if (XTYPE (Vstandard_display_table) == Lisp_Vector
2126 && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
2127 dp = XVECTOR (Vstandard_display_table);
2128
2129 if (tab_width <= 0 || tab_width > 20) tab_width = 8;
2130
2131 p1 = p1start;
2132 start = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
2133 end = start + window_width - (truncate != 0);
2134
2135 if ((window_width + XFASTINT (w->left))
2136 != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w))))
2137 *end-- = '|';
2138
2139 if (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol)
2140 end = desired_glyphs->glyphs[vpos] + maxcol;
2141 if (maxcol >= 0 && mincol > maxcol)
2142 mincol = maxcol;
2143
2144 while (p1 < end)
2145 {
2146 c = *string++;
2147 if (!c) break;
2148 if (c >= 040 && c < 0177
2149 && (dp == 0 || XTYPE (DISP_CHAR_ROPE (dp, c)) != Lisp_String))
2150 {
2151 if (p1 >= start)
2152 *p1 = c;
2153 p1++;
2154 }
2155 else if (c == '\t')
2156 {
2157 do
2158 {
2159 if (p1 >= start && p1 < end)
2160 *p1 = SPACEGLYPH;
2161 p1++;
2162 }
2163 while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
2164 }
2165 else if (dp != 0 && XTYPE (DISP_CHAR_ROPE (dp, c)) == Lisp_String)
2166 p1 = copy_rope (p1, start, DISP_CHAR_ROPE (dp, c));
2167 else if (c < 0200 && buffer_defaults.ctl_arrow)
2168 {
2169 if (p1 >= start)
2170 *p1 = (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
2171 ? XINT (DISP_CTRL_GLYPH (dp)) : '^');
2172 p1++;
2173 if (p1 >= start)
2174 *p1 = c ^ 0100;
2175 p1++;
2176 }
2177 else
2178 {
2179 if (p1 >= start)
2180 *p1 = (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
2181 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\');
2182 p1++;
2183 if (p1 >= start)
2184 *p1 = (c >> 6) + '0';
2185 p1++;
2186 if (p1 >= start)
2187 *p1 = (7 & (c >> 3)) + '0';
2188 p1++;
2189 if (p1 >= start)
2190 *p1 = (7 & c) + '0';
2191 p1++;
2192 }
2193 }
2194
2195 if (c)
2196 {
2197 p1 = end;
2198 if (truncate) *p1++ = truncate;
2199 }
2200 else if (mincol >= 0)
2201 {
2202 end = desired_glyphs->glyphs[vpos] + mincol;
2203 while (p1 < end)
2204 *p1++ = SPACEGLYPH;
2205 }
2206
2207 {
2208 register int len = p1 - desired_glyphs->glyphs[vpos];
2209
2210 if (len > desired_glyphs->used[vpos])
2211 desired_glyphs->used[vpos] = len;
2212 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
2213
2214 return len;
2215 }
2216}
2217\f
2218void
2219syms_of_xdisp ()
2220{
2221 staticpro (&last_arrow_position);
2222 staticpro (&last_arrow_string);
2223 last_arrow_position = Qnil;
2224 last_arrow_string = Qnil;
2225
2226 DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
2227 "String displayed by mode-line-format's \"%m\" specifiation.");
2228 Vglobal_mode_string = Qnil;
2229
2230 DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
2231 "Marker for where to display an arrow on top of the buffer text.\n\
2232This must be the beginning of a line in order to work.\n\
2233See also `overlay-arrow-string'.");
2234 Voverlay_arrow_position = Qnil;
2235
2236 DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
2237 "String to display as an arrow. See also `overlay-arrow-position'.");
2238 Voverlay_arrow_string = Qnil;
2239
2240 DEFVAR_INT ("scroll-step", &scroll_step,
2241 "*The number of lines to try scrolling a window by when point moves out.\n\
2242If that fails to bring point back on screen, point is centered instead.\n\
2243If this is zero, point is always centered after it moves off screen.");
2244
2245 DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
2246
2247 DEFVAR_BOOL ("truncate-partial-width-windows",
2248 &truncate_partial_width_windows,
2249 "*Non-nil means truncate lines in all windows less than full screen wide.");
2250 truncate_partial_width_windows = 1;
2251
2252 DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
2253 "*Non-nil means use inverse video for the mode line.");
2254 mode_line_inverse_video = 1;
2255
2256#ifndef MULTI_SCREEN
2257 defsubr (&Sredraw_display);
2258#endif /* MULTI_SCREEN */
2259}
2260
2261/* initialize the window system */
2262init_xdisp ()
2263{
2264 Lisp_Object root_window;
2265#ifndef COMPILER_REGISTER_BUG
2266 register
2267#endif /* COMPILER_REGISTER_BUG */
2268 struct window *mini_w;
2269
2270 this_line_bufpos = 0;
2271
2272 mini_w = XWINDOW (minibuf_window);
2273 root_window = mini_w->prev;
2274
2275 echo_area_glyphs = 0;
2276 previous_echo_glyphs = 0;
2277
2278 if (!noninteractive)
2279 {
2280 SCREEN_PTR s = XSCREEN (WINDOW_SCREEN (XWINDOW (root_window)));
2281 XFASTINT (XWINDOW (root_window)->top) = 0;
2282 set_window_height (root_window, SCREEN_HEIGHT (s) - 1, 0);
2283 XFASTINT (mini_w->top) = SCREEN_HEIGHT (s) - 1;
2284 set_window_height (minibuf_window, 1, 0);
2285
2286 XFASTINT (XWINDOW (root_window)->width) = SCREEN_WIDTH (s);
2287 XFASTINT (mini_w->width) = SCREEN_WIDTH (s);
2288 }
2289}