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