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