|
|
1.1 root 1: /* Display generation from window structure and buffer text.
2: Copyright (C) 1985 Richard M. Stallman.
3:
4: This file is part of GNU Emacs.
5:
6: GNU Emacs is distributed in the hope that it will be useful,
7: but WITHOUT ANY WARRANTY. No author or distributor
8: accepts responsibility to anyone for the consequences of using it
9: or for whether it serves any particular purpose or works at all,
10: unless he says so in writing. Refer to the GNU Emacs General Public
11: License for full details.
12:
13: Everyone is granted permission to copy, modify and redistribute
14: GNU Emacs, but only under the conditions described in the
15: GNU Emacs General Public License. A copy of this license is
16: supposed to have been given to you along with GNU Emacs so you
17: can know your rights and responsibilities. It should be in a
18: file named COPYING. Among other things, the copyright notice
19: and this notice must be preserved on all copies. */
20:
21:
22: #include "config.h"
23: #include <stdio.h>
24: #include <ctype.h>
25: #undef NULL
26: #include "lisp.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:
35: extern int interrupt_input;
36:
37: /* Nonzero means print newline before next minibuffer message. */
38:
39: int noninteractive_need_newline;
40:
41: #define min(a, b) ((a) < (b) ? (a) : (b))
42: #define max(a, b) ((a) > (b) ? (a) : (b))
43:
44: #define CURRENT_END_POS(w) \
45: (XFASTINT (w->window_end_pos) < 0 \
46: ? -1 - XFASTINT(w->window_end_pos) \
47: : XFASTINT(w->window_end_pos))
48:
49: /* The buffer position of the first character appearing
50: entirely or partially on the current screen line.
51: Or zero, which disables the optimization for the current screen line. */
52: int this_line_bufpos;
53:
54: /* Number of characters past the end of this line,
55: including the terminating newline */
56: int this_line_endpos;
57:
58: /* The vertical position of this screen line. */
59: int this_line_vpos;
60:
61: /* Hpos value for start of display on this screen line.
62: Usually zero, but negative if first character really began on previous line */
63: int this_line_hpos;
64:
65: /* Buffer that this_line variables are describing. */
66: struct buffer *this_line_buffer;
67:
68: /* Value of minibuf_message when it was last acted on.
69: If this is nonzero, there is a message on the screen
70: in the minibuffer and it should be erased as soon
71: as it is no longer requested to appear. */
72: char *prev_minibuf_message;
73:
74: /* Nonzero means truncate lines in all windows less wide than the screen */
75:
76: int truncate_partial_width_windows;
77:
78: Lisp_Object Vglobal_mode_string;
79:
80: Lisp_Object Vglobal_minor_modes;
81:
82: /* The number of lines to try scrolling a
83: window by when point leaves the window; if
84: it is <=0 then point is centered in the window */
85: int scroll_step;
86:
87: /* Nonzero if try_window_id has made blank lines at window bottom
88: since the last redisplay that paused */
89: int blank_end_of_window;
90:
91: /* Number of windows showing the buffer of the selected window. */
92: static int buffer_shared;
93:
94: /* display_text_line sets these to the screen position (origin 0) of point,
95: whether the window is selected or not.
96: Set one to -1 first to determine whether point was found afterwards. */
97:
98: int point_vpos;
99: int point_hpos;
100:
101: int debug_end_pos;
102:
103: extern int default_ctl_arrow; /* Nonzero means display ctl chars */
104: /* with uparrow in mode lines, etc */
105:
106: int mode_line_inverse_video; /* Nonzero means display mode line highlighted */
107:
108: struct position *display_text_line ();
109:
110: char *minibuf_prompt; /* Prompt to display in front of the minibuffer contents */
111:
112: /* Width in columns of current minibuffer prompt. */
113:
114: int minibuf_prompt_width;
115:
116: char *minibuf_message; /* Message to display instead of minibuffer contents
117: This is what the functions error and message make,
118: and command echoing uses it as well.
119: It overrides the minibuf_prompt as well as the buffer. */
120:
121: int RecurseDepth; /* Depth in recursive edits */
122:
123: int MinibufDepth; /* Depth in minibuffer invocations */
124:
125: int RedoModes; /* true iff we should redraw the mode lines
126: on the next redisplay */
127:
128: /* Minimum value of bf_s1 since last redisplay that finished.
129: Valid for current buffer unless Cant1WinOpt is nonzero. */
130:
131: int beg_unchanged;
132:
133: /* Minimum value of bf_s2 since last redisplay that finished.
134: Valid for current buffer unless Cant1WinOpt is nonzero. */
135:
136: int end_unchanged;
137:
138: /* bf_modified as of last redisplay that finished;
139: if it matches bf_modified, beg_unchanged and end_unchanged
140: contain no useful information */
141: int unchanged_modified;
142:
143: /* Nonzero if head_clip or tail_clip of current buffer has changed
144: since last redisplay that finished */
145: int clip_changed;
146:
147: /* Nonzero if window sizes or contents have changed
148: since last redisplay that finished */
149: int windows_or_buffers_changed;
150:
151: DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "",
152: "Clear the screen and output again what is supposed to appear on it.")
153: ()
154: {
155: if (screen_height == 0) abort (); /* Some bug zeros some core */
156: set_terminal_modes ();
157: clear_screen ();
158: fflush (stdout);
159: clear_screen_records ();
160: if (screen_height == 0) abort (); /* Some bug zeros some core */
161: windows_or_buffers_changed++;
162: /* Mark all windows as INaccurate,
163: so that every window will have its redisplay done. */
164: mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 0);
165: if (screen_height == 0) abort (); /* Some bug zeros some core */
166: return Qnil;
167: }
168:
169: static char message_buf[MScreenWidth + 1];
170:
171: /* dump an informative message to the minibuf */
172: /* VARARGS 1 */
173: message (m, a1, a2, a3)
174: char *m;
175: {
176: if (noninteractive)
177: {
178: if (noninteractive_need_newline)
179: putchar ('\n');
180: printf (m, a1, a2, a3);
181: printf ("\n");
182: fflush (stdout);
183: }
184: else if (INTERACTIVE)
185: {
186: doprnt (message_buf, sizeof message_buf - 1, m, &a1);
187: minibuf_message = message_buf;
188: display_minibuf_message ();
189: update_screen (1, 1);
190: }
191: }
192:
193: /* Specify m, a string, as a message in the minibuf. */
194: message1 (m)
195: char *m;
196: {
197: if (noninteractive)
198: {
199: if (noninteractive_need_newline)
200: putchar ('\n');
201: printf ("%s\n", m);
202: fflush (stdout);
203: }
204: else if (INTERACTIVE)
205: {
206: minibuf_message = m;
207: display_minibuf_message ();
208: update_screen (1, 1);
209: }
210: }
211:
212: display_minibuf_message ()
213: {
214: register int vpos;
215: register struct display_line *line;
216:
217: if (screen_garbaged)
218: {
219: Fredraw_display ();
220: screen_garbaged = 0;
221: }
222:
223: if (minibuf_message || !MinibufDepth)
224: {
225: vpos = XFASTINT (XWINDOW (minibuf_window)->top);
226: line = get_display_line (vpos, 0);
227: display_string (XWINDOW (minibuf_window), line,
228: minibuf_message ? minibuf_message : "",
229: 0, 0, 0);
230:
231: /* If desired cursor location is on this line, put it at end of text */
232: if (cursY == vpos)
233: cursX = line->length;
234: }
235: else if (!EQ (minibuf_window, selected_window))
236: windows_or_buffers_changed++;
237:
238: if (EQ (minibuf_window, selected_window))
239: this_line_bufpos = 0;
240:
241: prev_minibuf_message = minibuf_message;
242: }
243:
244: /* Do a screen update, taking possible shortcuts into account.
245: This is the main external entry point for redisplay */
246:
247: DoDsp (SaveMiniBuf)
248: {
249: register struct window *w = XWINDOW (selected_window);
250: register int pause;
251: int inhibit_hairy_id = 0;
252: int must_finish = 0;
253: int all_windows = 0;
254: register int tlbufpos, tlendpos;
255: struct position pos;
256: extern int input_pending;
257:
258: if (noninteractive)
259: return;
260:
261: if (screen_garbaged)
262: {
263: Fredraw_display ();
264: screen_garbaged = 0;
265: }
266:
267: if (minibuf_message ||
268: (prev_minibuf_message && !SaveMiniBuf))
269: {
270: display_minibuf_message ();
271: must_finish = 1;
272: }
273:
274: if (clip_changed || windows_or_buffers_changed)
275: RedoModes++;
276:
277: /* Detect case that we need to write a star in the mode line. */
278: if (XFASTINT (w->last_modified) < bf_modified
279: && XFASTINT (w->last_modified) <= bf_cur->save_modified)
280: {
281: w->redo_mode_line = Qt;
282: if (buffer_shared > 1)
283: RedoModes++;
284: }
285:
286: all_windows = RedoModes || buffer_shared > 1;
287:
288: tlbufpos = this_line_bufpos;
289: tlendpos = this_line_endpos;
290: if (!all_windows && tlbufpos > 0 && NULL (w->redo_mode_line)
291: /* Point must be on the line that we have info recorded about */
292: && point >= tlbufpos
293: && point <= bf_s1 + bf_s2 + 1 - tlendpos
294: /* All text outside that line, including its final newline,
295: must be unchanged */
296: && (XFASTINT (w->last_modified) >= bf_modified
297: || (beg_unchanged >= tlbufpos - 1
298: && bf_s1 >= tlbufpos - 1
299: && end_unchanged >= tlendpos
300: && bf_s2 >= tlendpos))
301: /* Make sure recorded data applies to current buffer, etc */
302: && NULL (w->force_start)
303: && bf_cur == XBUFFER (w->buffer)
304: && this_line_buffer == bf_cur)
305: {
306: if (tlbufpos > FirstCharacter && CharAt (tlbufpos - 1) != '\n'
307: && (tlbufpos == NumCharacters + 1
308: || CharAt (tlbufpos) == '\n'))
309: /* Former continuation line has disappeared by becoming empty */
310: ;
311: else if (XFASTINT (w->last_modified) < bf_modified
312: || EQ (selected_window, minibuf_window))
313: {
314: point_vpos = -1;
315: display_text_line (w, tlbufpos, this_line_vpos, this_line_hpos,
316: pos_tab_offset (w, tlbufpos));
317: /* If line contains point, is not continued,
318: and ends at same distance from eob as before, we win */
319: if (point_vpos >= 0 && this_line_bufpos
320: && this_line_endpos == tlendpos)
321: {
322: cursX = point_hpos;
323: if (XFASTINT (w->width) != screen_width)
324: preserve_other_columns (w);
325: if (interrupt_input)
326: unrequest_sigio ();
327: goto update;
328: }
329: }
330: else if (point == XFASTINT (w->last_point))
331: {
332: if (!must_finish)
333: return;
334: goto update;
335: }
336: else
337: {
338: pos = *compute_motion (tlbufpos, 0,
339: XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
340: point, 2, - (1 << (SHORTBITS - 1)),
341: XFASTINT (w->width) - 1
342: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width),
343: XINT (w->hscroll), 0);
344: if (pos.vpos < 1)
345: {
346: cursX = max (XFASTINT (w->left), pos.hpos);
347: if (interrupt_input)
348: unrequest_sigio ();
349: goto update;
350: }
351: }
352: /* Text changed drastically or point moved off of line */
353: cancel_line (this_line_vpos);
354: }
355:
356: this_line_bufpos = 0;
357:
358: if (interrupt_input)
359: unrequest_sigio ();
360:
361: if (all_windows)
362: redisplay_all_windows ();
363: else
364: {
365: inhibit_hairy_id = redisplay_window (selected_window, 1);
366: if (XFASTINT (w->width) != screen_width)
367: preserve_other_columns (w);
368: }
369:
370: update:
371: pause = update_screen (0, inhibit_hairy_id);
372:
373: /* If screen does not match, prevent doing single-line-update next time */
374: if (pause)
375: this_line_bufpos = 0;
376:
377: /* Now text on screen agrees with windows, so
378: put info into the windows for partial redisplay to follow */
379:
380: if (!pause)
381: {
382: register struct buffer_text *t
383: = XBUFFER (w->buffer) == bf_cur
384: ? &bf_text : &XBUFFER (w->buffer)->text;
385:
386: blank_end_of_window = 0;
387: clip_changed = 0;
388: unchanged_modified = t->modified;
389: beg_unchanged = t->size1, end_unchanged = t->size2;
390:
391: XFASTINT (w->last_point) = t->pointloc;
392: XFASTINT (w->last_point_x) = cursX;
393: XFASTINT (w->last_point_y) = cursY;
394:
395: if (all_windows)
396: mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 1);
397: else
398: {
399: w->redo_mode_line = Qnil;
400: XFASTINT (w->last_modified) = t->modified;
401: if (XFASTINT (w->window_end_pos) < 0)
402: XFASTINT (w->window_end_pos) = -1 - XFASTINT (w->window_end_pos);
403: }
404: RedoModes = 0;
405: windows_or_buffers_changed = 0;
406: }
407:
408: /* Start SIGIO interrupts coming again.
409: Having them off during the code above
410: makes it less likely one will discard output,
411: but not impossible, since there might be stuff
412: in the system buffer here.
413: But it is much hairier to try to do anything about that. */
414:
415: if (interrupt_input)
416: request_sigio ();
417: }
418:
419: mark_window_display_accurate (window, flag)
420: Lisp_Object window;
421: int flag;
422: {
423: register struct window *w;
424:
425: for (;!NULL (window); window = w->next)
426: {
427: w = XWINDOW (window);
428:
429: XFASTINT (w->last_modified)
430: = !flag ? 0
431: : XBUFFER (w->buffer) == bf_cur
432: ? bf_modified : XBUFFER (w->buffer)->text.modified;
433: if (XFASTINT (w->window_end_pos) < 0)
434: XFASTINT (w->window_end_pos) = -1 - XFASTINT (w->window_end_pos);
435: w->redo_mode_line = Qnil;
436:
437: if (!NULL (w->vchild))
438: mark_window_display_accurate (w->vchild, flag);
439: if (!NULL (w->hchild))
440: mark_window_display_accurate (w->hchild, flag);
441: }
442: }
443:
444: int do_id = 1;
445:
446: /* Do full redisplay of one or all windows.
447: This does not include updating the screen;
448: just generating lines to pass to update_screen. */
449:
450: /* Entry point to redisplay all windows */
451:
452: redisplay_all_windows ()
453: {
454: buffer_shared = 0;
455:
456: redisplay_windows (XWINDOW (minibuf_window)->prev);
457: }
458:
459: redisplay_windows (window)
460: Lisp_Object window;
461: {
462: for (; !NULL (window); window = XWINDOW (window)->next)
463: redisplay_window (window, 0);
464: }
465:
466: redisplay_window (window, just_this_one)
467: Lisp_Object window;
468: int just_this_one;
469: {
470: register struct window *w = XWINDOW (window);
471: int height;
472: register int lpoint = point;
473: struct buffer *old = bf_cur;
474: register int width = XFASTINT (w->width) - 1
475: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width);
476: register int startp = marker_position (w->start);
477: register int hscroll = XINT (w->hscroll);
478: struct position pos;
479: int inhibit_hairy_id = 0;
480: int opoint;
481: int tem;
482:
483: if (screen_height == 0) abort (); /* Some bug zeros some core */
484:
485: /* If this is a combination window, do its children; that's all. */
486:
487: if (!NULL (w->vchild))
488: {
489: redisplay_windows (w->vchild);
490: return 0;
491: }
492: if (!NULL (w->hchild))
493: {
494: redisplay_windows (w->hchild);
495: return 0;
496: }
497: if (NULL (w->buffer))
498: abort ();
499:
500: if (RedoModes)
501: w->redo_mode_line = Qt;
502:
503: /* Otherwise set up data on this window; select its buffer and point value */
504:
505: height = XFASTINT (w->height);
506: if (w != XWINDOW (minibuf_window))
507: height--;
508: else if (minibuf_message)
509: return 0;
510:
511: SetBfx (XBUFFER (w->buffer));
512: opoint = point;
513:
514: if (!just_this_one
515: && bf_cur == XBUFFER (XWINDOW (selected_window)->buffer))
516: buffer_shared++;
517:
518: if (!EQ (window, selected_window))
519: {
520: SetPoint (marker_position (w->pointm));
521: if (point < FirstCharacter)
522: point = FirstCharacter;
523: else if (point > NumCharacters)
524: point = NumCharacters + 1;
525: }
526:
527: /* Handle case where place to start displaying has been specified */
528:
529: if (!NULL (w->force_start))
530: {
531: w->redo_mode_line = Qt;
532: w->force_start = Qnil;
533: XFASTINT (w->last_modified) = 0;
534: if (!try_window (window, startp))
535: {
536: /* If point does not appear, move point so it does appear */
537: pos = *compute_motion (startp, 0,
538: ((EQ (window, minibuf_window) && startp == 1)
539: ? minibuf_prompt_width : 0)
540: +
541: (hscroll ? 1 - hscroll : 0),
542: NumCharacters + 1, height / 2,
543: - (1 << (SHORTBITS - 1)),
544: width, hscroll, pos_tab_offset (w, startp));
545: SetPoint (pos.bufpos);
546: if (w != XWINDOW (selected_window))
547: Fset_marker (w->pointm, make_number (point), Qnil);
548: else
549: lpoint = point;
550:
551: if (EQ (window, selected_window))
552: {
553: cursX = max (0, pos.hpos) + XFASTINT (w->left);
554: cursY = pos.vpos + XFASTINT (w->top);
555: }
556: }
557: goto done;
558: }
559:
560: /* Handle case where text has not changed, only point,
561: and it has not moved off the screen */
562:
563: /* This code is not used for minibuffer for the sake of
564: the case of redisplaying to replace an echo area message;
565: since in that case the minibuffer contents per se are usually unchanged.
566: This code is of no real use in the minibuffer since
567: the handling of tlbufpos, etc., in DoDsp handles the same cases. */
568:
569: if (XFASTINT (w->last_modified) >= bf_modified
570: && point >= startp && !clip_changed
571: && (just_this_one || XFASTINT (w->width) == screen_width)
572: && !EQ (window, minibuf_window))
573: {
574: pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
575: point, height + 1, 10000, width, hscroll,
576: pos_tab_offset (w, startp));
577:
578: if (pos.vpos < height)
579: {
580: /* Ok, point is still on screen */
581: if (w == XWINDOW (selected_window))
582: {
583: /* These variables are supposed to be origin 1 */
584: cursX = max (0, pos.hpos) + XFASTINT (w->left);
585: cursY = pos.vpos + XFASTINT (w->top);
586: }
587: /* This doesn't do the trick, because if a window to the right of
588: this one must be redisplayed, this does nothing because there
589: is nothing in DesiredScreen yet, and then the other window is
590: redisplayed, making likes that are empty in this window's columns.
591: if (XFASTINT (w->width) != screen_width)
592: preserve_my_columns (w);
593: */
594: goto done;
595: }
596: /* Don't bother trying redisplay with same start;
597: we already know it will lose */
598: }
599: else if (just_this_one && !EQ (window, minibuf_window)
600: && point >= startp
601: && XFASTINT (w->last_modified)
602: && XFASTINT (w->window_end_pos) >= 0
603: && do_id && !clip_changed
604: && !blank_end_of_window
605: && XFASTINT (w->width) == screen_width
606: && (tem = try_window_id (selected_window))
607: && tem != -2)
608: {
609: /* tem > 0 means success. tem == -1 means choose new start.
610: tem == -2 means try again with same start,
611: and nothing but whitespace follows the changed stuff.
612: tem == 0 means try again with same start. */
613: if (tem > 0)
614: {
615: /* inhibit_hairy_id = 1; */
616: goto done;
617: }
618: }
619: else if (startp >= FirstCharacter && startp <= NumCharacters + 1
620: /* Avoid starting display at end of buffer! */
621: && (startp <= NumCharacters || startp == FirstCharacter
622: || (XFASTINT (w->last_modified) >= bf_modified)))
623: {
624: /* Try to redisplay starting at same place as before */
625: /* If point has not moved off screen, accept the results */
626: if (try_window (window, startp))
627: goto done;
628: else
629: cancel_my_columns (w);
630: }
631:
632: XFASTINT (w->last_modified) = 0;
633: w->redo_mode_line = Qt;
634:
635: /* Try to scroll by specified few lines */
636:
637: if (scroll_step && !clip_changed)
638: {
639: if (point > startp)
640: {
641: pos = *vmotion (bf_s1 + bf_s2 + 1 - CURRENT_END_POS (w),
642: scroll_step, width, hscroll, window);
643: if (pos.vpos >= height)
644: goto scroll_fail;
645: }
646:
647: pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step,
648: width, hscroll, window);
649:
650: if (point >= pos.bufpos)
651: {
652: if (try_window (window, pos.bufpos))
653: goto done;
654: else
655: cancel_my_columns (w);
656: }
657: scroll_fail: ;
658: }
659:
660: /* Finally, just choose place to start which centers point */
661:
662: pos = *vmotion (point, - height / 2, width, hscroll, window);
663: try_window (window, pos.bufpos);
664:
665: done:
666: /* If window not full width, must redo its mode line
667: if the window to its side is being redone */
668: if ((!NULL (w->redo_mode_line)
669: || (!just_this_one && width < screen_width - 1))
670: && !EQ (window, minibuf_window))
671: display_mode_line (w);
672:
673: SetPoint (opoint);
674: SetBfx (old);
675: SetPoint (lpoint);
676:
677: return inhibit_hairy_id;
678: }
679:
680: /* Do full redisplay on one window,
681: starting at position `pos',
682: and return nonzero if point appears in the displayed text */
683:
684: try_window (window, pos)
685: Lisp_Object window;
686: register int pos;
687: {
688: register struct window *w = XWINDOW (window);
689: register int height = XFASTINT (w->height) - !EQ (window, minibuf_window);
690: register int vpos = XFASTINT (w->top);
691: register int last_text_vpos = vpos;
692: int tab_offset = pos_tab_offset (w, pos);
693:
694: struct position val;
695:
696: Fset_marker (w->start, make_number (pos), Qnil);
697:
698: point_vpos = -1;
699: val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
700:
701: while (--height >= 0)
702: {
703: val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
704: tab_offset += XFASTINT (w->width) - 1;
705: if (val.vpos) tab_offset = 0;
706: vpos++;
707: if (pos != val.bufpos)
708: last_text_vpos
709: /* Next line, unless prev line ended in end of buffer with no cr */
710: = vpos - (val.vpos && CharAt (val.bufpos - 1) != '\n');
711: pos = val.bufpos;
712: }
713:
714: /* If last line is continued in middle of character,
715: include the split character in the text considered on the screen */
716: if (val.hpos < XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0)
717: pos++;
718:
719: /* Make this -1 minus what it really should be, so that it is negative.
720: That serves as a signal that it is not really valid.
721: When screen updating is through,
722: change this to its correct positive value */
723: XFASTINT (w->window_end_pos) = -1 - (bf_s1 + bf_s2 + 1 - pos);
724: XFASTINT (w->window_end_vpos) = last_text_vpos - XFASTINT (w->top);
725: return point_vpos >= 0;
726: }
727:
728: /* Try to redisplay when buffer is modified locally,
729: computing insert/delete line to preserve text outside
730: the bounds of the changes.
731: Return 1 if successful, 0 if if cannot tell what to do,
732: or -1 to tell caller to find a new window start,
733: or -2 to tell caller that we did nothing because only whitespace
734: appears below the changed part of the screen. */
735:
736: try_window_id (window)
737: Lisp_Object window;
738: {
739: int pos;
740: register struct window *w = XWINDOW (window);
741: register int height = XFASTINT (w->height) - !EQ (window, minibuf_window);
742: int top = XFASTINT (w->top);
743: int start = marker_position (w->start);
744: int width = XFASTINT (w->width) - 1
745: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width);
746: int hscroll = XINT (w->hscroll);
747: int lmargin = hscroll > 0 ? 1 - hscroll : 0;
748: register int vpos;
749: register int i, tem;
750: int last_text_vpos = 0;
751: int stop_vpos;
752:
753: struct position val, bp, ep, xp, pp;
754: int scroll_amount = 0;
755: int delta;
756: int tab_offset, epto;
757:
758: if (bf_s1 < beg_unchanged)
759: beg_unchanged = bf_s1;
760: if (bf_s2 < end_unchanged)
761: end_unchanged = bf_s2;
762:
763: if (beg_unchanged + 1 < start)
764: return 0; /* Give up if changes go above top of window */
765:
766: /* Find position before which nothing is changed. */
767: bp = *compute_motion (start, 0, lmargin,
768: beg_unchanged + 1, 10000, 10000, width, hscroll,
769: pos_tab_offset (w, start));
770: if (bp.vpos >= height)
771: return point < bp.bufpos && !bp.contin;
772:
773: vpos = bp.vpos;
774:
775: /* Find beginning of that screen line. Must display from there. */
776: bp = *vmotion (bp.bufpos, 0, width, hscroll, window);
777:
778: pos = bp.bufpos;
779: val.hpos = lmargin;
780: if (pos < start)
781: return -1;
782:
783: /* If about to start displaying at the beginning of a continuation line,
784: really start with previous screen line, in case it was not
785: continued when last redisplayed */
786: if (bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0)
787: {
788: bp = *vmotion (bp.bufpos, -1, width, hscroll, window);
789: --vpos;
790: pos = bp.bufpos;
791: }
792:
793: if (bp.contin && bp.hpos != lmargin)
794: {
795: val.hpos = bp.prevhpos - width + lmargin;
796: pos--;
797: }
798:
799: bp.vpos = vpos;
800:
801: /* Find first newline after which no more is changed */
802: ep = *compute_motion (pos, vpos, val.hpos,
803: ScanBf ('\n',
804: bf_s1 + bf_s2 + 1 - max (end_unchanged, bf_tail_clip),
805: 1),
806: height, - (1 << (SHORTBITS - 1)),
807: width, hscroll, pos_tab_offset (w, bp.bufpos));
808:
809: /* If changes reach past the text available on the screen,
810: just display rest of screen. */
811: if (ep.bufpos > bf_s1 + bf_s2 + 1 - XFASTINT (w->window_end_pos))
812: stop_vpos = height;
813: else
814: stop_vpos = ep.vpos;
815:
816: /* If no newline before ep, the line ep is on includes some changes
817: that must be displayed. Make sure we don't stop before it. */
818: /* Also, if changes reach all the way until ep.bufpos,
819: it is possible that something was deleted after the
820: newline before it, so the following line must be redrawn. */
821: if (stop_vpos == ep.vpos
822: && (ep.bufpos == FirstCharacter
823: || CharAt (ep.bufpos - 1) != '\n'
824: || ep.bufpos == bf_s1 + bf_s2 + 1 - end_unchanged))
825: stop_vpos = ep.vpos + 1;
826:
827: point_vpos = -1;
828:
829: /* If changes do not reach to bottom of window,
830: figure out how much to scroll the rest of the window */
831: if (stop_vpos < height)
832: {
833: /* Now determine how far up or down the rest of the window has moved */
834: epto = pos_tab_offset (w, ep.bufpos);
835: xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
836: bf_s1 + bf_s2 + 1 - XFASTINT (w->window_end_pos),
837: 10000, 0, width, hscroll, epto);
838: scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
839:
840: /* Is everything on screen below the changes whitespace?
841: If so, no scrolling is really necessary. */
842: for (i = ep.bufpos; i < xp.bufpos; i++)
843: {
844: tem = CharAt (i);
845: if (tem != ' ' && tem != '\n' && tem != '\t')
846: break;
847: }
848: if (i == xp.bufpos)
849: return -2;
850:
851: XFASTINT (w->window_end_vpos) += scroll_amount;
852:
853: /* Before doing any scrolling, verify that point will be on screen. */
854: if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height))
855: {
856: if (point <= xp.bufpos)
857: {
858: pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
859: point, height, - (1 << (SHORTBITS - 1)),
860: width, hscroll, epto);
861: }
862: else
863: {
864: pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
865: point, height, - (1 << (SHORTBITS - 1)),
866: width, hscroll, pos_tab_offset (w, xp.bufpos));
867: }
868: if (pp.bufpos < point || pp.vpos == height)
869: return 0;
870: point_vpos = pp.vpos + top;
871: point_hpos = pp.hpos + XFASTINT (w->left);
872: }
873:
874: if (stop_vpos - scroll_amount >= height
875: || ep.bufpos == xp.bufpos)
876: {
877: if (scroll_amount < 0)
878: stop_vpos -= scroll_amount;
879: scroll_amount = 0;
880: /* In this path, we have altered window_end_vpos
881: and not left it negative.
882: We must make sure that, in case display is preempted
883: before the screen changes to reflect what we do here,
884: further updates will not come to try_window_id
885: and assume the screen and window_end_vpos match. */
886: blank_end_of_window = 1;
887: }
888: else if (!scroll_amount)
889: {}
890: else if (bp.bufpos == bf_s1 + bf_s2 + 1 - end_unchanged)
891: {
892: /* If pure deletion, scroll up as many lines as possible.
893: In common case of killing a line, this can save the
894: following line from being overwritten by scrolling
895: and therefore having to be redrawn. */
896: tem = scroll_screen_lines (bp.vpos + top - scroll_amount,
897: top + height - max (0, scroll_amount),
898: scroll_amount);
899: if (!tem) stop_vpos = height;
900: }
901: else if (scroll_amount)
902: {
903: tem = scroll_screen_lines (ep.vpos + top - scroll_amount,
904: top + height - max (0, scroll_amount),
905: scroll_amount);
906: if (!tem) stop_vpos = height;
907: }
908: }
909:
910: /* In any case, do not display past bottom of window */
911: if (stop_vpos >= height)
912: {
913: stop_vpos = height;
914: scroll_amount = 0;
915: }
916:
917: /* Handle case where pos is before w->start --
918: can happen if part of line had been clipped and is not clipped now */
919: if (vpos == 0 && pos < marker_position (w->start))
920: Fset_marker (w->start, make_number (pos), Qnil);
921:
922: /* Redisplay the lines where the text was changed */
923: last_text_vpos = vpos;
924: tab_offset = pos_tab_offset (w, pos);
925: if (val.hpos < 0)
926: tab_offset += XFASTINT (w->width) - 1;
927: while (vpos < stop_vpos)
928: {
929: val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
930: tab_offset += XFASTINT (w->width) - 1;
931: if (val.vpos) tab_offset = 0;
932: if (pos != val.bufpos)
933: last_text_vpos
934: /* Next line, unless prev line ended in end of buffer with no cr */
935: = vpos - (val.vpos && CharAt (val.bufpos - 1) != '\n');
936: pos = val.bufpos;
937: }
938:
939: /* There are two cases:
940: 1) we have displayed down to the bottom of the window
941: 2) we have scrolled lines below stop_vpos by scroll_amount */
942:
943: if (vpos == height)
944: {
945: /* If last line is continued in middle of character,
946: include the split character in the text considered on the screen */
947: if (val.hpos < lmargin)
948: val.bufpos++;
949: XFASTINT (w->window_end_vpos) = last_text_vpos;
950: XFASTINT (w->window_end_pos) = -1 - (bf_s1 + bf_s2 + 1 - val.bufpos);
951: }
952:
953: /* If scrolling made blank lines at window bottom,
954: redisplay to fill those lines */
955: if (scroll_amount < 0)
956: {
957: vpos = xp.vpos;
958: pos = xp.bufpos;
959: val.hpos = lmargin;
960: if (pos == NumCharacters + 1)
961: vpos = height + scroll_amount;
962: else if (xp.contin && xp.hpos != lmargin)
963: {
964: val.hpos = xp.prevhpos - width + lmargin;
965: pos--;
966: }
967:
968: blank_end_of_window = 1;
969: tab_offset = pos_tab_offset (w, pos);
970: if (val.hpos < 0)
971: tab_offset += XFASTINT (w->width) - 1;
972:
973: while (vpos < height)
974: {
975: val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
976: tab_offset += XFASTINT (w->width) - 1;
977: if (val.vpos) tab_offset = 0;
978: pos = val.bufpos;
979: }
980:
981: /* Here is a case where display_line_text sets point_vpos wrong.
982: Make it be fixed up, below. */
983: if (xp.bufpos == NumCharacters + 1
984: && xp.bufpos == point)
985: point_vpos = -1;
986: }
987:
988: /* Attempt to adjust end-of-text positions to new bottom line */
989: if (scroll_amount)
990: {
991: delta = height - xp.vpos;
992: if (delta < 0
993: || (delta > 0 && xp.bufpos <= NumCharacters)
994: || (delta == 0 && xp.hpos))
995: {
996: val = *vmotion (bf_s1 + bf_s2 + 1 - XFASTINT (w->window_end_pos),
997: delta, width, hscroll, window);
998: XFASTINT (w->window_end_pos) = bf_s1 + bf_s2 + 1 - val.bufpos;
999: XFASTINT (w->window_end_vpos) += val.vpos;
1000: }
1001: }
1002:
1003: /* If point was not in a line that was displayed, find it */
1004: if (point_vpos < 0)
1005: {
1006: val = *compute_motion (start, 0, lmargin, point, 10000, 10000,
1007: width, hscroll, pos_tab_offset (w, start));
1008: /* Admit failure if point is off screen now */
1009: if (val.vpos >= height)
1010: {
1011: for (vpos = 0; vpos < height; vpos++)
1012: cancel_line (vpos + top);
1013: return 0;
1014: }
1015: point_vpos = val.vpos + top;
1016: point_hpos = val.hpos + XFASTINT (w->left);
1017: }
1018:
1019: cursX = max (0, point_hpos);
1020: cursY = point_vpos;
1021:
1022: if (debug_end_pos)
1023: {
1024: val = *compute_motion (start, 0, lmargin, NumCharacters + 1,
1025: height, - (1 << (SHORTBITS - 1)),
1026: width, hscroll, pos_tab_offset (w, start));
1027: if (val.vpos != XFASTINT (w->window_end_vpos))
1028: abort ();
1029: if ((XFASTINT (w->window_end_pos) < 0
1030: ? -1 - XFASTINT (w->window_end_pos)
1031: : XFASTINT (w->window_end_pos))
1032: != bf_s1 + bf_s2 + 1 - val.bufpos)
1033: abort ();
1034: }
1035:
1036: return 1;
1037: }
1038:
1039: /* Display one line of window w, starting at position `start' in w's buffer.
1040: Display starting at horizontal position `hpos',
1041: which is normally zero or negative.
1042: A negative value causes output up to hpos = 0 to be discarded.
1043: This is done for negative hscroll, or when this is a continuation line
1044: and the continuation occurred in the middle of a multi-column character.
1045:
1046: `taboffset' is an offset for ostensible hpos, used in tab stop calculations.
1047:
1048: Display on position `vpos' on the screen. (origin 0).
1049:
1050: Returns a `struct position' giving character to start next line with
1051: and where to display it, including a zero or negative hpos.
1052: The vpos field is not really a vpos; it is 1 unless the line is continued */
1053:
1054: struct position val_display_text_line;
1055:
1056: struct position *
1057: display_text_line (w, start, vpos, hpos, taboffset)
1058: struct window *w;
1059: int start;
1060: int vpos;
1061: int hpos;
1062: int taboffset;
1063: {
1064: register int pos = start;
1065: register int c;
1066: register char *p1;
1067: int end;
1068: register int pause;
1069: register unsigned char *p;
1070: char *endp;
1071: register char *startp;
1072: register char *p1prev;
1073: register struct display_line *line;
1074: int tab_width = XFASTINT (XBUFFER (w->buffer)->tab_width);
1075: int ctl_arrow = !NULL (XBUFFER (w->buffer)->ctl_arrow);
1076: int width = XFASTINT (w->width) - 1
1077: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width);
1078: struct position val;
1079: int lastpos;
1080: int invis;
1081: int hscroll = XINT (w->hscroll);
1082: int truncate = hscroll
1083: || (truncate_partial_width_windows
1084: && XFASTINT (w->width) < screen_width)
1085: || !NULL (XBUFFER (w->buffer)->truncate_lines);
1086: int selective
1087: = XTYPE (bf_cur->selective_display) == Lisp_Int
1088: ? XINT (bf_cur->selective_display)
1089: : !NULL (bf_cur->selective_display) ? -1 : 0;
1090:
1091: hpos += XFASTINT (w->left);
1092: line = get_display_line (vpos, XFASTINT (w->left));
1093: if (tab_width <= 0) tab_width = 1;
1094:
1095: if (w == XWINDOW (minibuf_window) && start == 1)
1096: {
1097: if (minibuf_prompt)
1098: hpos = display_string (w, line, minibuf_prompt, hpos,
1099: !truncate ? '\\' : '$',
1100: 0);
1101: minibuf_prompt_width = hpos;
1102: }
1103:
1104: p1 = line->body + hpos;
1105:
1106: end = NumCharacters + 1;
1107:
1108: startp = line->body + XFASTINT (w->left);
1109: endp = startp + width;
1110:
1111: /* Loop generating characters.
1112: Stop at end of buffer, before newline,
1113: or if reach or pass continuation column. */
1114:
1115: pause = pos;
1116: while (p1 < endp)
1117: {
1118: p1prev = p1;
1119: if (pos == pause)
1120: {
1121: if (pos == end)
1122: break;
1123: if (pos == point && point_vpos < 0)
1124: {
1125: point_vpos = vpos;
1126: point_hpos = p1 - startp;
1127: }
1128:
1129: pause = end;
1130: if (pos < point && point < pause)
1131: pause = point;
1132: if (pos <= bf_s1 && bf_s1 + 1 < pause)
1133: pause = bf_s1 + 1;
1134:
1135: p = &CharAt (pos);
1136: }
1137: c = *p++;
1138: if (c >= 040 && c < 0177)
1139: {
1140: if (p1 >= startp)
1141: *p1 = c;
1142: p1++;
1143: }
1144: else if (c == '\n')
1145: {
1146: invis = 0;
1147: while (pos < end
1148: && selective > 0
1149: && position_indentation (pos + 1) >= selective)
1150: {
1151: invis = 1;
1152: pos = ScanBf ('\n', pos + 1, 1);
1153: if (CharAt (pos - 1) == '\n')
1154: pos--;
1155: }
1156: if (invis)
1157: {
1158: p1 += 4;
1159: if (p1 - startp > width)
1160: p1 = endp;
1161: strncpy (p1prev, " ...", p1 - p1prev);
1162: }
1163: break;
1164: }
1165: else if (c == '\t')
1166: {
1167: do
1168: {
1169: if (p1 >= startp)
1170: *p1 = ' ';
1171: p1++;
1172: }
1173: while ((p1 - startp + taboffset + hscroll - (hscroll > 0))
1174: % tab_width);
1175: }
1176: else if (c == Ctl('M') && !NULL (bf_cur->selective_display))
1177: {
1178: pos = ScanBf ('\n', pos, 1);
1179: if (CharAt (pos - 1) == '\n')
1180: pos--;
1181: break;
1182: }
1183: else if (c < 0200 && ctl_arrow)
1184: {
1185: if (p1 >= startp)
1186: *p1 = '^';
1187: p1++;
1188: if (p1 >= startp)
1189: *p1 = c ^ 0100;
1190: p1++;
1191: }
1192: else
1193: {
1194: if (p1 >= startp)
1195: *p1 = '\\';
1196: p1++;
1197: if (p1 >= startp)
1198: *p1 = (c >> 6) + '0';
1199: p1++;
1200: if (p1 >= startp)
1201: *p1 = (7 & (c >> 3)) + '0';
1202: p1++;
1203: if (p1 >= startp)
1204: *p1 = (7 & c) + '0';
1205: p1++;
1206: }
1207: pos++;
1208: }
1209:
1210: val.hpos = - XINT (w->hscroll);
1211: if (val.hpos)
1212: {
1213: val.hpos++;
1214: /* If line not empty, insert truncation-at-left marker */
1215: if (pos != start)
1216: {
1217: *startp = '$';
1218: if (p1 <= startp)
1219: p1 = startp + 1;
1220: if (line->length <= XFASTINT (w->left))
1221: line->length = XFASTINT (w->left) + 1;
1222: }
1223: }
1224: val.vpos = 1;
1225:
1226: /* Handle continuation in middle of a character */
1227: /* by backing up over it */
1228: if (p1 > endp)
1229: {
1230: /* Start the next line with that same character */
1231: pos--;
1232: /* but at a negative hpos, to skip the columns output on this line. */
1233: val.hpos += p1prev - endp;
1234: /* Keep in this line everything up to the continuation column. */
1235: p1 = endp;
1236: }
1237:
1238: /* Finish deciding which character to start the next line on,
1239: and what hpos to start it at.
1240: Also set `lastpos' to the last position which counts as "on this line"
1241: for cursor-positioning. */
1242:
1243: lastpos = pos;
1244:
1245: if (pos < NumCharacters + 1)
1246: {
1247: if (CharAt (pos) == '\n')
1248: /* If stopped due to a newline, start next line after it */
1249: pos++;
1250: else
1251: /* Stopped due to right margin of window */
1252: {
1253: if (truncate)
1254: {
1255: *p1++ = '$';
1256: /* Truncating => start next line after next newline,
1257: and point is on this line if it is before the newline,
1258: and skip none of first char of next line */
1259: pos = ScanBf ('\n', pos, 1);
1260: val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
1261:
1262: lastpos = pos - (CharAt (pos - 1) == '\n');
1263: }
1264: else
1265: {
1266: *p1++ = '\\';
1267: val.vpos = 0;
1268: lastpos = 0;
1269: }
1270: }
1271: }
1272:
1273: if (start <= point && point <= lastpos && point_vpos < 0)
1274: {
1275: point_vpos = vpos;
1276: point_hpos = p1 - startp;
1277: }
1278:
1279: if (point_vpos == vpos)
1280: {
1281: if (point_hpos < 0) point_hpos = 0;
1282: if (point_hpos > width) point_hpos = width;
1283: point_hpos += XFASTINT (w->left);
1284: if (w == XWINDOW (selected_window))
1285: {
1286: cursY = point_vpos;
1287: cursX = point_hpos;
1288:
1289: /* Line is not continued and did not start in middle of character */
1290: if (hpos == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0)
1291: && val.vpos)
1292: {
1293: this_line_bufpos = start;
1294: this_line_buffer = bf_cur;
1295: this_line_vpos = vpos;
1296: this_line_hpos = hpos;
1297: this_line_endpos = bf_s1 + bf_s2 + 1 - lastpos;
1298: }
1299: else
1300: this_line_bufpos = 0;
1301: }
1302: }
1303:
1304: if (XFASTINT (w->width) + XFASTINT (w->left) != screen_width)
1305: {
1306: endp++;
1307: if (p1 < startp) p1 = startp;
1308: while (p1 < endp) *p1++ = ' ';
1309: *p1++ = '|';
1310: }
1311: line->length = max (line->length, p1 - line->body);
1312: line->body[line->length] = 0;
1313:
1314: val.bufpos = pos;
1315: val_display_text_line = val;
1316: return &val_display_text_line;
1317: }
1318:
1319: /* Display the mode line for window w */
1320:
1321: display_mode_line (w)
1322: struct window *w;
1323: {
1324: int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
1325: struct display_line *line = get_display_line (vpos, XFASTINT (w->left));
1326:
1327: register unsigned char *s = XSTRING (bf_cur->mode_line_format)->data;
1328:
1329: display_string (w, line, s, XFASTINT (w->left), 0, 1);
1330: /* Make the mode line inverse video if the entire line
1331: is made of mode lines.
1332: I.e. if this window is full width,
1333: or if it is the child of a full width window
1334: (which implies that that window is split side-by-side
1335: and the rest of this line is mode lines of the sibling windows). */
1336: if (XFASTINT (w->width) == screen_width
1337: || XFASTINT (XWINDOW (w->parent)->width) == screen_width)
1338: line->highlighted = mode_line_inverse_video;
1339: }
1340:
1341: char fmodetrunc_buf[100];
1342:
1343: char *
1344: fmodetrunc (str, width)
1345: char *str;
1346: long width;
1347: {
1348: register char *buf = fmodetrunc_buf;
1349: register char *bp = buf;
1350: register long len;
1351:
1352: len = strlen(str);
1353: if (width && width < len)
1354: {
1355: strcpy(buf,str+len-width);
1356: if (buf[0] != '/')
1357: while (*bp)
1358: if (*bp++ == '/')
1359: {
1360: bp--;
1361: *--bp = '$';
1362: return bp;
1363: }
1364: buf[0] = '$';
1365: return buf;
1366: }
1367: return str;
1368: }
1369:
1370: char decode_mode_spec_buf[MScreenWidth + 1];
1371:
1372: char *
1373: decode_mode_spec (w, string, data_ptr, len_ptr, max_ptr)
1374: struct window *w;
1375: register char *string;
1376: char **data_ptr;
1377: int *len_ptr;
1378: int *max_ptr;
1379: {
1380: register int width = 0;
1381: register char c;
1382: Lisp_Object lstr, proc, list;
1383: register char *str;
1384: int len;
1385: int pos, total;
1386: char *tbuf = decode_mode_spec_buf;
1387: #define tbufsize (sizeof decode_mode_spec_buf)
1388:
1389: lstr = Qnil, str = 0;
1390:
1391: while (isdigit (c = *string++))
1392: width = width * 10 + (c - '0');
1393:
1394: switch (c)
1395: {
1396: case 'b':
1397: lstr = bf_cur->name;
1398: if (width && XSTRING (lstr)->size > width)
1399: width = min (2 * width, XSTRING (lstr)->size);
1400: if (width && XSTRING (lstr)->size > width)
1401: {
1402: str = (char *) alloca (width + 1);
1403: bcopy (XSTRING (lstr)->data, str, width - 3);
1404: bcopy ("...", str + width - 3, 4);
1405: lstr = Qnil;
1406: }
1407: break;
1408:
1409: case 'f':
1410: if (NULL (bf_cur->filename))
1411: str = "[none]";
1412: else if (XTYPE (bf_cur->filename) == Lisp_String)
1413: str = fmodetrunc (XSTRING (bf_cur -> filename)->data, width);
1414: break;
1415:
1416: case 'm':
1417: lstr = bf_cur->mode_name;
1418: total = min (XSTRING (lstr)->size, tbufsize - 30);
1419: if (total < 0) total = 0;
1420: bcopy (XSTRING (lstr)->data, tbuf, total);
1421: len = 0;
1422: list = bf_cur->minor_modes;
1423: while (1)
1424: {
1425: if (!LISTP (list) && !len)
1426: {
1427: list = Vglobal_minor_modes;
1428: len = 1;
1429: }
1430:
1431: if (!(total < tbufsize - 30 && LISTP (list)))
1432: break;
1433:
1434: lstr = XCONS (list)->car;
1435: if (!LISTP (lstr))
1436: goto foo;
1437: lstr = XCONS (lstr)->cdr;
1438: if (XTYPE (lstr) != Lisp_String)
1439: goto foo;
1440: tbuf[total++] = ' ';
1441: pos = min (XSTRING (lstr)->size, tbufsize - 30 - total);
1442: if (pos < 0)
1443: pos = 0;
1444: bcopy (XSTRING (lstr)->data, tbuf + total, pos);
1445: total += pos;
1446: foo:
1447: list = Fcdr (list);
1448: }
1449: str = tbuf;
1450: tbuf[total] = 0;
1451: /* if (bf_cur->abbrev_mode)
1452: strcat (tbuf, " Abbrev"); */
1453: if (bf_head_clip > 1 || bf_tail_clip > 0)
1454: strcat (tbuf, " Narrow");
1455: if (defining_kbd_macro)
1456: strcat (tbuf, " Def");
1457: lstr = Qnil;
1458: break;
1459:
1460: case 'M':
1461: lstr = Vglobal_mode_string;
1462: break;
1463:
1464: case '*':
1465: str = !NULL (bf_cur->read_only) ? "%"
1466: : bf_modified > bf_cur->save_modified ? "*" :"-";
1467: break;
1468:
1469: case 's':
1470: /* status of process */
1471: #ifdef subprocesses
1472: proc = Fget_buffer_process (Fcurrent_buffer ());
1473: if (NULL (proc))
1474: str = "no process";
1475: else
1476: lstr = Fsymbol_name (Fprocess_status (proc));
1477: #else
1478: str = "no process";
1479: #endif /* subprocesses */
1480: break;
1481:
1482: case 'p':
1483: pos = marker_position (w->start);
1484: total = NumCharacters + 1 - FirstCharacter;
1485:
1486: if ((XFASTINT (w->window_end_pos) < 0
1487: ? -1 - XFASTINT (w->window_end_pos)
1488: : XFASTINT (w->window_end_pos))
1489: <= bf_tail_clip)
1490: {
1491: if (pos <= FirstCharacter)
1492: str = "All";
1493: else
1494: str = "Bottom";
1495: }
1496: else if (pos <= FirstCharacter)
1497: str = "Top";
1498: else
1499: {
1500: total = ((pos - FirstCharacter) * 100 + total - 1) / total;
1501: /* We can't normally display a 3-digit number,
1502: so get us a 2-digit number that is close. */
1503: if (total == 100)
1504: total = 99;
1505: sprintf (tbuf, "%2d%%", total);
1506: str = tbuf;
1507: }
1508: break;
1509:
1510: case '[':
1511: str = "[[[[[[[[[[" + 10 - (RecurseDepth - MinibufDepth);
1512: if (RecurseDepth - MinibufDepth > 10)
1513: str = "[[[... ";
1514: break;
1515:
1516: case ']':
1517: str = "]]]]]]]]]]" + 10 - (RecurseDepth - MinibufDepth);
1518: if (RecurseDepth - MinibufDepth > 10)
1519: str = " ...]]]";
1520: break;
1521:
1522: case '-':
1523: str = "--------------------------------------------------------------------------------------------------------------------------------------------";
1524: }
1525:
1526: /* Report the chosen mode item to the caller */
1527:
1528: if (str)
1529: *data_ptr = str, *len_ptr = strlen (str);
1530: else if (XTYPE (lstr) == Lisp_String)
1531: *data_ptr = (char *) XSTRING (lstr)->data,
1532: *len_ptr = XSTRING (lstr)->size;
1533: else
1534: *data_ptr = 0, *len_ptr = 0;
1535:
1536: /* Report specified truncation or padding */
1537:
1538: *max_ptr = width;
1539:
1540: /* Tell caller how much of mode line format was used up */
1541:
1542: return string;
1543: }
1544:
1545: /* Display `string' on one line of window `w', starting at `hpos'.
1546: Display on the display_line `line', which should have
1547: been obtained by get_display_line (vpos, hpos)
1548: or in some suitable manner.
1549:
1550: `truncate' is character to display at end if truncated.
1551: `modeline' nonzero means substitute for % constructs.
1552:
1553: Returns ending hpos */
1554:
1555:
1556: display_string (w, line, string, hpos, truncate, modeline)
1557: struct window *w;
1558: register struct display_line *line;
1559: unsigned char *string;
1560: int hpos;
1561: int truncate;
1562: int modeline;
1563: {
1564: register int c;
1565: register unsigned char *p1;
1566: int width = XFASTINT (w->width) - 1
1567: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width);
1568: int hscroll = XINT (w->hscroll);
1569: int tab_width = 8;
1570: register unsigned char *start;
1571: register unsigned char *end;
1572: char *modeeltstring;
1573: int modeeltleft = 0;
1574: int modeeltmax = 0;
1575:
1576: p1 = (unsigned char *) line->body + hpos;
1577: start = (unsigned char *) line->body + XFASTINT (w->left);
1578: end = start + width;
1579:
1580: while (p1 < end)
1581: {
1582: if (modeeltmax)
1583: {
1584: modeeltmax--;
1585: if (modeeltleft-- > 0)
1586: c = *modeeltstring++;
1587: else
1588: c = ' ';
1589: }
1590: else
1591: {
1592: c = *string++;
1593: if (!c) break;
1594: if (c == '%' && modeline)
1595: {
1596: string = (unsigned char *)
1597: decode_mode_spec (w, string, &modeeltstring,
1598: &modeeltleft, &modeeltmax);
1599:
1600: if (!modeeltmax)
1601: modeeltmax = modeeltleft;
1602: else if (modeeltleft > modeeltmax)
1603: modeeltleft = modeeltmax;
1604:
1605: continue;
1606: }
1607: }
1608:
1609: if (c >= 040 && c < 0177)
1610: {
1611: if (p1 >= start)
1612: *p1 = c;
1613: p1++;
1614: }
1615: else if (c == '\t')
1616: {
1617: do
1618: {
1619: if (p1 >= start)
1620: *p1 = ' ';
1621: p1++;
1622: }
1623: while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
1624: }
1625: else if (c < 0200 && default_ctl_arrow)
1626: {
1627: if (p1 >= start)
1628: *p1 = '^';
1629: p1++;
1630: if (p1 >= start)
1631: *p1 = c ^ 0100;
1632: p1++;
1633: }
1634: else
1635: {
1636: if (p1 >= start)
1637: *p1 = '\\';
1638: p1++;
1639: if (p1 >= start)
1640: *p1 = (c >> 6) + '0';
1641: p1++;
1642: if (p1 >= start)
1643: *p1 = (7 & (c >> 3)) + '0';
1644: p1++;
1645: if (p1 >= start)
1646: *p1 = (7 & c) + '0';
1647: p1++;
1648: }
1649: }
1650:
1651: if (c)
1652: {
1653: p1 = end;
1654: if (truncate) *p1++ = truncate;
1655: }
1656:
1657: line->length = max (line->length, p1 - (unsigned char *) line->body);
1658: line->body[line->length] = 0;
1659: return p1 - (unsigned char *) line->body;
1660: }
1661:
1662: syms_of_xdisp ()
1663: {
1664: DefLispVar ("global-mode-string", &Vglobal_mode_string,
1665: "String which mode line can display (if its format requests to).");
1666: Vglobal_mode_string = Qnil;
1667:
1668: DefLispVar ("global-minor-modes", &Vglobal_minor_modes,
1669: "Alist of minor modes that are not per buffer.\n\
1670: Cdr of each element is a string to display in mode line.");
1671:
1672: DefIntVar ("scroll-step", &scroll_step,
1673: "*The number of lines to try scrolling a window by when point moves out.\n\
1674: If that fails to bring point back on screen, point is centered instead.\n\
1675: If this is zero, point is always centered after it moves off screen.");
1676:
1677: DefIntVar ("debug-end-pos", &debug_end_pos, "Don't ask");
1678:
1679: DefBoolVar ("truncate-partial-width-windows",
1680: &truncate_partial_width_windows,
1681: "*Non-nil means truncate lines in all windows less than full screen wide.");
1682: truncate_partial_width_windows = 1;
1683:
1684: DefBoolVar ("mode-line-inverse-video", &mode_line_inverse_video,
1685: "*Non-nil means use inverse video, or other suitable display mode, for the mode line.");
1686: mode_line_inverse_video = 1;
1687:
1688: defsubr (&Sredraw_display);
1689: }
1690:
1691: /* initialize the window system */
1692: init_xdisp ()
1693: {
1694: Lisp_Object root_window;
1695: #ifndef COMPILER_REGISTER_BUG
1696: register
1697: #endif COMPILER_REGISTER_BUG
1698: struct window *mini_w;
1699:
1700: this_line_bufpos = 0;
1701:
1702: mini_w = XWINDOW (minibuf_window);
1703: root_window = mini_w->prev;
1704:
1705: minibuf_message = 0;
1706: prev_minibuf_message = 0;
1707:
1708: if (!noninteractive)
1709: {
1710: XFASTINT (XWINDOW (root_window)->top) = 0;
1711: set_window_height (root_window, screen_height - 1, 0);
1712: XFASTINT (mini_w->top) = screen_height - 1;
1713: set_window_height (minibuf_window, 1, 0);
1714:
1715: XFASTINT (XWINDOW (root_window)->width) = screen_width;
1716: XFASTINT (mini_w->width) = screen_width;
1717: }
1718: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.