|
|
1.1 root 1: /* Newly written part of redisplay code.
2: Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
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 <signal.h>
23:
24: #include "config.h"
25: #include <stdio.h>
26:
27: #ifdef HAVE_TIMEVAL
28: #ifdef HPUX
29: #include <time.h>
30: #else
31: #include <sys/time.h>
32: #endif
33: #endif
34:
35: #ifdef HAVE_TERMIO
36: #include <termio.h>
37: #ifdef TCOUTQ
38: #undef TIOCOUTQ
39: #define TIOCOUTQ TCOUTQ
40: #endif /* TCOUTQ defined */
41: #else
42: #ifndef VMS
43: #include <sys/ioctl.h>
44: #endif /* not VMS */
45: #endif /* not HAVE_TERMIO */
46:
47: /* Allow m- file to inhibit use of FIONREAD. */
48: #ifdef BROKEN_FIONREAD
49: #undef FIONREAD
50: #undef SIGIO
51: #endif
52:
53: #undef NULL
54:
55: #include "termchar.h"
56: #include "termopts.h"
57: #include "cm.h"
58: #include "dispextern.h"
59: #include "lisp.h"
60: #include "buffer.h"
61: #include "window.h"
62: #include "commands.h"
63:
64: #define max(a, b) ((a) > (b) ? (a) : (b))
65: #define min(a, b) ((a) < (b) ? (a) : (b))
66:
67: #ifndef PENDING_OUTPUT_COUNT
68: /* Get number of chars of output now in the buffer of a stdio stream.
69: This ought to be built in in stdio, but it isn't.
70: Some s- files override this because their stdio internals differ. */
71: #define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_ptr - (FILE)->_base)
72: #endif
73:
74: /* Nonzero means do not assume anything about current
75: contents of actual terminal screen */
76:
77: int screen_garbaged;
78:
79: /* Desired terminal cursor position (to show position of point),
80: origin zero */
81:
82: int cursX, cursY;
83:
84: /* Nonzero means last display completed and cursor is really at cursX, cursY.
85: Zero means it was preempted. */
86:
87: int display_completed;
88:
89: int visible_bell; /* If true and the terminal will support it
90: then the screen will flash instead of
91: feeping when an error occurs */
92: int inverse_video; /* If true and the terminal will support it
93: then we will use inverse video */
94:
95: int baud_rate; /* Terminal speed, so we can calculate
96: the number of characters required to
97: make the cursor sit still for n secs. */
98:
99: Lisp_Object Vwindow_system; /* nil or a symbol naming the window system
100: under which emacs is running
101: ('x is the only current possibility) */
102:
103: /* Version number of window system, or nil if no window system. */
104: Lisp_Object Vwindow_system_version;
105:
106: /* Nonzero means reading single-character input with prompt
107: so put cursor on minibuffer after the prompt. */
108:
109: int cursor_in_echo_area;
110:
111: /* the current (physical) screen */
112: struct display_line *PhysScreen[MScreenLength + 1];
113:
114: /* temporary Copy of PhysScreen made in update_screen */
115: struct display_line *OPhysScreen[MScreenLength + 1];
116:
117: /* the desired (virtual) screen */
118: struct display_line *DesiredScreen[MScreenLength + 1];
119:
120: /* Record here all the display line objects, for debugging. */
121: static struct display_line *all_lines[2 * MScreenLength];
122:
123: FILE *termscript; /* Stdio stream being used for copy of all kbdinput. */
124:
125: struct cm Wcm; /* Structure for info on cursor positioning */
126:
127: extern short ospeed; /* Output speed (from sg_ospeed) */
128:
129: int in_display; /* 1 if in redisplay: can't handle SIGWINCH now. */
130:
131: int delayed_size_change; /* 1 means SIGWINCH happened when not safe. */
132: int delayed_screen_height; /* Remembered new screen height. */
133: int delayed_screen_width; /* Remembered new screen width. */
134:
135: /* Use these to chain together free lines */
136:
137: #define LINE_NEXT(l) (*(struct display_line **) l)
138: #define SET_LINE_NEXT(l, next) (*((struct display_line **) l) = next)
139:
140: /* Chain of free display_line structures, chained thru LINE_NEXT. */
141:
142: struct display_line *free_display_lines;
143:
144: /* Number of lines now free. */
145:
146: int free_line_count;
147:
148: /* Allocate as many display_line structures
149: as we are ever supposed to need.
150: Called at startup, and also if screen size is changed. */
151:
152: make_display_lines ()
153: {
154: register int i;
155: register struct display_line *p, *p1;
156:
157: /* First, free any that are already allocated */
158:
159: for (p = free_display_lines; p;)
160: {
161: p1 = p;
162: p = LINE_NEXT (p);
163: free (p1);
164: }
165: free_display_lines = 0;
166: free_line_count = 0;
167:
168: for (i = 0; i <= MScreenLength; i++)
169: if (PhysScreen[i])
170: {
171: free (PhysScreen[i]);
172: PhysScreen[i] = 0;
173: }
174:
175: screen_garbaged = 1;
176:
177: /* Now allocate as many as we can possibly validly need */
178:
179: for (i = - screen_height; i < screen_height; i++)
180: {
181: p = (struct display_line *) malloc (sizeof (struct display_line) + screen_width - MScreenWidth);
182: if (!p) abort ();
183: SET_LINE_NEXT (p, free_display_lines);
184: free_display_lines = p;
185: all_lines[i + screen_height] = p;
186: }
187: free_line_count = 2 * screen_height;
188: }
189:
190: /* Get one of the previously malloc'd display_line structures
191: from the free pool. */
192:
193: struct display_line *
194: new_display_line ()
195: {
196: register struct display_line *p = free_display_lines;
197: /* If we ever use up all the display lines that have been
198: allocated, it indicates a bug, since we are supposed
199: to need at most two for each line on the screen. */
200: if (!p)
201: abort ();
202: free_display_lines = LINE_NEXT (p);
203:
204: bzero (p, p->body - (char *) p);
205: SET_LINE_NEXT (p, (struct display_line *)1); /* Mark as in use. */
206: free_line_count--;
207: return p;
208: }
209:
210: /* Put a display_line back in the free pool. */
211:
212: return_display_line (p)
213: struct display_line *p;
214: {
215: if (!p)
216: return;
217: if ((int) LINE_NEXT (p) != 1)
218: abort (); /* Already free. */
219: SET_LINE_NEXT (p, free_display_lines);
220: free_display_lines = p;
221: free_line_count++;
222: }
223:
224: clear_screen_records ()
225: {
226: register int i;
227: for (i = 1; i <= screen_height; i++)
228: if (PhysScreen[i])
229: return_display_line (PhysScreen[i]);
230: bzero (PhysScreen, (screen_height + 1) * sizeof PhysScreen[0]);
231: }
232:
233: /* Return the hash code of display_line p. */
234: line_hash_code (p)
235: register struct display_line *p;
236: {
237: register char *body, *end;
238: register int h = 0;
239: if (!p)
240: return 0;
241: /* Give all lighlighted lines the same hash code
242: so as to encourage scrolling to leave them in place. */
243: if (p->highlighted)
244: return -1;
245:
246: body = p->body;
247: end = body + p->length;
248: *end = 0;
249: if (!must_write_spaces)
250: {
251: while (*body++ == ' ');
252: body--;
253: if (body == end)
254: return 1;
255: while (end[-1] == ' ') end--;
256: }
257: while (body != end)
258: h = (h << 5) + h + *body++;
259: if (h)
260: return h;
261: return 1;
262: }
263:
264: /* Return number of characters in display_line p,
265: except don't count leading and trailing spaces
266: unless the terminal requires those to be explicitly output. */
267:
268: line_draw_cost (p)
269: struct display_line *p;
270: {
271: register char *body;
272: register int i;
273:
274: if (!p)
275: return 0;
276:
277: if (must_write_spaces)
278: return p->length;
279:
280: body = p->body - 1;
281: for (i = p->length; i > 0 && body[i - 1] == ' '; i--);
282:
283: i -= count_blanks (p->body);
284: return max (i, 0);
285: }
286:
287: /* The functions on this page are the interface from xdisp.c to redisplay.
288: They take cursor position arguments in origin 0.
289:
290: The only other interface into redisplay is through setting
291: cursX and cursY (in xdisp.c) and setting screen_garbaged. */
292:
293: /* cancel_line eliminates any request to display a line at position `vpos' */
294:
295: cancel_line (vpos)
296: int vpos;
297: {
298: return_display_line (DesiredScreen[vpos + 1]);
299: DesiredScreen[vpos + 1] = 0;
300: }
301:
302: /* Get a display_line for displaying on line `vpos'
303: and set it up for outputting starting at `hpos' within it. */
304:
305: struct display_line *
306: get_display_line (vpos, hpos)
307: int vpos;
308: register int hpos;
309: {
310: register struct display_line *line;
311: register char *p;
312:
313: if (vpos < 0) abort ();
314:
315: line = DesiredScreen[vpos + 1];
316: if (line && line->length > hpos)
317: abort ();
318: if (!line)
319: line = new_display_line ();
320:
321: if (hpos > line->length)
322: {
323: p = line->body + line->length;
324: hpos -= line->length;
325: line->length += hpos;
326: while (--hpos >= 0)
327: *p++ = ' ';
328: }
329:
330: DesiredScreen[vpos + 1] = line;
331:
332: return line;
333: }
334:
335: /* Scroll lines from vpos `from' up to but not including vpos `end'
336: down by `amount' lines (`amount' may be negative).
337: Returns nonzero if done, zero if terminal cannot scroll them. */
338:
339: int
340: scroll_screen_lines (from, end, amount)
341: int from, end, amount;
342: {
343: register int i;
344:
345: if (!line_ins_del_ok)
346: return 0;
347:
348: if (amount == 0)
349: return 1;
350: if (amount > 0)
351: {
352: set_terminal_window (end + amount);
353: if (!scroll_region_ok)
354: ins_del_lines (end, -amount);
355: ins_del_lines (from, amount);
356: set_terminal_window (0);
357:
358: for (i = end + amount; i >= end + 1; i--)
359: return_display_line (PhysScreen[i]);
360: for (i = end; i >= from + 1; i--)
361: PhysScreen[i + amount] = PhysScreen[i];
362: for (i = from + amount; i >= from + 1; i--)
363: PhysScreen[i] = 0;
364: }
365: if (amount < 0)
366: {
367: set_terminal_window (end);
368: ins_del_lines (from + amount, amount);
369: if (!scroll_region_ok)
370: ins_del_lines (end + amount, -amount);
371: set_terminal_window (0);
372:
373: for (i = from + amount + 1; i <= from; i++)
374: return_display_line (PhysScreen[i]);
375: for (i = from + 1; i <= end ; i++)
376: PhysScreen[i + amount] = PhysScreen[i];
377: for (i = end + amount + 1; i <= end; i++)
378: PhysScreen[i] = 0;
379: }
380: return 1;
381: }
382:
383: /* After updating a window w that isn't the full screen wide,
384: copy all the columns that w does not occupy
385: into the DesiredScreen lines from the PhysScreen lines
386: so that update_screen will not change those columns. */
387:
388: preserve_other_columns (w)
389: struct window *w;
390: {
391: register int vpos;
392: register struct display_line *l1, *l2;
393: int start = XFASTINT (w->left);
394: int end = XFASTINT (w->left) + XFASTINT (w->width);
395: int bot = XFASTINT (w->top) + XFASTINT (w->height);
396:
397: for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
398: {
399: if ((l1 = DesiredScreen[vpos + 1])
400: && (l2 = PhysScreen[vpos + 1]))
401: {
402: if (start > 0)
403: {
404: bcopy (l2->body, l1->body, start);
405: if (l1->length < start && l1->length < l2->length)
406: l1->length = min (start, l2->length);
407: }
408: if (l2->length > end && l1->length < l2->length)
409: {
410: while (l1->length < end)
411: l1->body[l1->length++] = ' ';
412: bcopy (l2->body + end, l1->body + end, l2->length - end);
413: l1->length = l2->length;
414: }
415: }
416: }
417: }
418:
419: #ifdef NOTDEF
420:
421: /* If window w does not need to be updated and isn't the full screen wide,
422: copy all the columns that w does occupy
423: into the DesiredScreen lines from the PhysScreen lines
424: so that update_screen will not change those columns.
425:
426: Have not been able to figure out how to use this correctly. */
427:
428: preserve_my_columns (w)
429: struct window *w;
430: {
431: register int vpos, fin;
432: register struct display_line *l1, *l2;
433: int start = XFASTINT (w->left);
434: int end = XFASTINT (w->left) + XFASTINT (w->width);
435: int bot = XFASTINT (w->top) + XFASTINT (w->height);
436:
437: for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
438: {
439: if ((l1 = DesiredScreen[vpos + 1])
440: && (l2 = PhysScreen[vpos + 1]))
441: {
442: if (l2->length > start && l1->length < l2->length)
443: {
444: fin = l2->length;
445: if (fin > end) fin = end;
446: while (l1->length < start)
447: l1->body[l1->length++] = ' ';
448: bcopy (l2->body + start, l1->body + start, fin - start);
449: l1->length = fin;
450: }
451: }
452: }
453: }
454:
455: #endif /* NOTDEF */
456:
457: /* On discovering that the redisplay for a window was no good,
458: cancel the columns of that window,
459: so that when the window is displayed over again
460: get_display_line will not complain. */
461:
462: cancel_my_columns (w)
463: struct window *w;
464: {
465: register int vpos;
466: register struct display_line *l;
467: register int start = XFASTINT (w->left);
468: register int bot = XFASTINT (w->top) + XFASTINT (w->height);
469:
470: for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
471: {
472: if ((l = DesiredScreen[vpos + 1])
473: && l->length >= start)
474: l->length = start;
475: }
476: }
477:
478: /* These functions try to perform directly and immediately on the screen
479: the necessary output for one change in the buffer.
480: They may return 0 meaning nothing was done if anything is difficult,
481: or 1 meaning the output was performed properly.
482: They assume that the screen was up to date before the buffer
483: change being displayed. THey make various other assumptions too;
484: see command_loop_1 where these are called. */
485:
486: int
487: direct_output_for_insert (c)
488: int c;
489: {
490: register struct display_line *p = PhysScreen[cursY + 1];
491: #ifndef COMPILER_REGISTER_BUG
492: register
493: #endif COMPILER_REGISTER_BUG
494: struct window *w = XWINDOW (selected_window);
495: #ifndef COMPILER_REGISTER_BUG
496: register
497: #endif COMPILER_REGISTER_BUG
498: int hpos = cursX;
499:
500: /* Give up if about to continue line */
501: if (hpos - XFASTINT (w->left) + 1 + 1 >= XFASTINT (w->width)
502:
503: /* Avoid losing if cursor is in invisible text off left margin */
504: || XINT (w->hscroll) && hpos == XFASTINT (w->left)
505:
506: /* Give up if cursor outside window (in minibuf, probably) */
507: || cursY < XFASTINT (w->top)
508: || cursY >= XFASTINT (w->top) + XFASTINT (w->height)
509:
510: /* Give up if cursor not really at cursX, cursY */
511: || !display_completed
512:
513: /* Give up if w is minibuffer and a message is being displayed there */
514: || EQ (selected_window, minibuf_window) && minibuf_message)
515: return 0;
516:
517: p->body[hpos] = c;
518: unchanged_modified = bf_modified;
519: beg_unchanged = bf_s1;
520: XFASTINT (w->last_point) = point;
521: XFASTINT (w->last_point_x) = cursX;
522: XFASTINT (w->last_modified) = bf_modified;
523:
524: reassert_line_highlight (0, cursY);
525: write_chars (p->body + hpos, 1);
526: fflush (stdout);
527: ++cursX;
528: p->length = max (p->length, cursX);
529: p->body[p->length] = 0;
530: return 1;
531: }
532:
533: int
534: direct_output_forward_char (n)
535: int n;
536: {
537: register struct window *w = XWINDOW (selected_window);
538:
539: /* Avoid losing if cursor is in invisible text off left margin */
540: if (XINT (w->hscroll) && cursX == XFASTINT (w->left))
541: return 0;
542:
543: cursX += n;
544: XFASTINT (w->last_point_x) = cursX;
545: XFASTINT (w->last_point) = point;
546: topos (cursY, cursX);
547: fflush (stdout);
548: return 1;
549: }
550:
551: /* Update the actual terminal screen based on the data in DesiredScreen.
552: Value is nonzero if redisplay stopped due to pending input.
553: FORCE nonzero means do not stop for pending input. */
554:
555: /* At the time this function is called,
556: no line is common to PhysScreen and DesiredScreen.
557: That is true again when this function returns. */
558:
559: update_screen (force, inhibit_hairy_id)
560: int force;
561: int inhibit_hairy_id;
562: {
563: register struct display_line **p;
564: register struct display_line *l, *lnew;
565: register int i;
566: int pause;
567: int preempt_count;
568: extern input_pending;
569:
570: if (screen_height == 0) abort (); /* Some bug zeros some core */
571:
572: bcopy (PhysScreen, OPhysScreen, sizeof PhysScreen);
573:
574: detect_input_pending ();
575: if (input_pending && !force)
576: {
577: pause = 1;
578: goto do_pause;
579: }
580:
581: update_begin ();
582:
583: if (!line_ins_del_ok)
584: inhibit_hairy_id = 1;
585:
586: /* Don't compute for i/d line if just want cursor motion. */
587: for (p = &DesiredScreen[screen_height]; p != DesiredScreen && *p == 0; p--);
588:
589: /* Try doing i/d line, if not yet inhibited. */
590: if (!inhibit_hairy_id && p != DesiredScreen)
591: force |= scrolling ();
592:
593: /* Update the individual lines as needed. Do bottom line first. */
594:
595: l = DesiredScreen[screen_height];
596: if (l && l != PhysScreen[screen_height])
597: update_line (PhysScreen[screen_height], l, screen_height - 1);
598: preempt_count = baud_rate / 2400;
599: for (i = 1; i < screen_height && (force || !input_pending); i++)
600: {
601: l = PhysScreen[i];
602: lnew = DesiredScreen[i];
603: if (lnew && lnew != l)
604: {
605: /* Flush out every so many lines.
606: Also flush out if likely to have more than 1k buffered
607: otherwise. I'm told that telnet connections get really
608: screwed by more than 1k output at once. */
609: int outq = PENDING_OUTPUT_COUNT (stdout);
610: if (outq > ((--preempt_count < 0) ? 20 : 900))
611: {
612: fflush (stdout);
613: if (baud_rate < 2400)
614: {
615: #ifdef TIOCOUTQ
616: if (ioctl (0, TIOCOUTQ, &outq) < 0)
617: /* Probably not a tty. Ignore the error and reset
618: * the outq count. */
619: outq = PENDING_OUTPUT_COUNT (stdout);
620: #endif
621: outq *= 10;
622: outq /= baud_rate; /* outq is now in seconds */
623: if (outq)
624: sleep (outq);
625: }
626: detect_input_pending ();
627:
628: preempt_count = baud_rate / 2400;
629: }
630: /* Now update this line. */
631: update_line (l, lnew, i - 1);
632: }
633: }
634: pause = (i < screen_height) ? i : 0;
635:
636: /* Now just clean up termcap drivers and set cursor, etc. */
637: if (!pause)
638: {
639: if (cursor_in_echo_area < 0)
640: topos (screen_height - 1, 0);
641: else if (cursor_in_echo_area)
642: topos (screen_height - 1,
643: (PhysScreen[screen_height] == 0 ? 0
644: : min (screen_width - 1,
645: PhysScreen[screen_height]->length)));
646: else
647: topos (cursY, max (min (cursX, screen_width - 1), 0));
648: }
649:
650: update_end ();
651:
652: if (termscript)
653: fflush (termscript);
654: fflush (stdout);
655:
656: /* Here if output is preempted because input is detected. */
657: do_pause:
658:
659: if (screen_height == 0) abort (); /* Some bug zeros some core */
660: display_completed = !pause;
661: /* Free any lines still in desired screen but not in phys screen */
662: /* Free any lines that used to be in phys screen but are no longer */
663: for (p = &PhysScreen[screen_height]; p != PhysScreen; p--)
664: if (p[0]) p[0]->physical = 1;
665: for (p = &DesiredScreen[screen_height]; p != DesiredScreen; p--)
666: {
667: if (l = *p)
668: {
669: if (!l->physical)
670: {
671: return_display_line (l);
672: /* Prevent line in both DesiredScreen and OPhysScreen
673: from being freed twice. */
674: l->physical = 1;
675: }
676: }
677: }
678: for (p = &OPhysScreen[screen_height]; p != OPhysScreen; p--)
679: {
680: if (l = *p)
681: {
682: if (!l->physical)
683: return_display_line (l);
684: }
685: }
686: i = 0;
687: for (p = &PhysScreen[screen_height]; p != PhysScreen; p--)
688: if (p[0])
689: {
690: i++;
691: p[0]->physical = 0;
692: }
693:
694: {
695: extern int debug_end_pos;
696: if (debug_end_pos && i + free_line_count != 2 * screen_height)
697: abort ();
698: }
699:
700: bzero (OPhysScreen, (screen_height + 1) * sizeof OPhysScreen[0]);
701: bzero (DesiredScreen, (screen_height + 1) * sizeof DesiredScreen[0]);
702: return pause;
703: }
704:
705: /* Called when about to quit, to check for doing so
706: at an improper time. */
707:
708: void
709: quit_error_check ()
710: {
711: if (DesiredScreen[1] != 0)
712: abort ();
713: if (DesiredScreen[screen_height] != 0)
714: abort ();
715: }
716:
717: /* Decide what insert/delete line to do, and do it */
718:
719: scrolling ()
720: {
721: int unchanged_at_top, unchanged_at_bottom;
722: int window_size;
723: int changed_lines;
724: int *old_hash = (int *) alloca (screen_height * sizeof (int));
725: int *new_hash = (int *) alloca (screen_height * sizeof (int));
726: int *draw_cost = (int *) alloca (screen_height * sizeof (int));
727: register int i;
728: int free_at_end_vpos = screen_height;
729:
730: /* Compute hash codes of all the lines.
731: Also calculate number of changed lines,
732: number of unchanged lines at the beginning,
733: and number of unchanged lines at the end. */
734:
735: changed_lines = 0;
736: unchanged_at_top = 0;
737: unchanged_at_bottom = screen_height;
738: for (i = 0; i < screen_height; i++)
739: {
740: old_hash[i] = line_hash_code (PhysScreen[i + 1]);
741: if (!DesiredScreen[i + 1])
742: DesiredScreen[i + 1] = PhysScreen[i + 1];
743: if (PhysScreen[i + 1] == DesiredScreen[i + 1])
744: new_hash[i] = old_hash[i];
745: else
746: new_hash[i] = line_hash_code (DesiredScreen[i + 1]);
747: if (old_hash[i] != new_hash[i])
748: {
749: changed_lines++;
750: unchanged_at_bottom = screen_height - i - 1;
751: }
752: else if (i == unchanged_at_top)
753: unchanged_at_top++;
754: draw_cost[i] = line_draw_cost (DesiredScreen[i + 1]);
755: }
756:
757: /* If changed lines are few, don't allow preemption, don't scroll. */
758: if (changed_lines < baud_rate / 2400 || unchanged_at_bottom == screen_height)
759: return 1;
760:
761: window_size = screen_height - unchanged_at_top - unchanged_at_bottom;
762:
763: if (scroll_region_ok)
764: free_at_end_vpos -= unchanged_at_bottom;
765: else if (memory_below_screen)
766: free_at_end_vpos = -1;
767:
768: /* If large window, fast terminal and few lines in common between
769: PhysScreen and DesiredScreen, don't bother with i/d calc. */
770: if (window_size >= 18 && baud_rate > 2400
771: && (window_size >=
772: 10 * scrolling_max_lines_saved (unchanged_at_top,
773: screen_height - unchanged_at_bottom,
774: old_hash, new_hash, draw_cost)))
775: return 0;
776:
777: scrolling_1 (window_size, unchanged_at_top, unchanged_at_bottom,
778: draw_cost + unchanged_at_top - 1,
779: old_hash + unchanged_at_top - 1,
780: new_hash + unchanged_at_top - 1,
781: free_at_end_vpos - unchanged_at_top);
782:
783: return 0;
784: }
785:
786: update_line (old, new, vpos)
787: struct display_line *old, *new;
788: int vpos;
789: {
790: register char *obody, *nbody, *op1, *op2, *np1;
791: int tem;
792: int osp, nsp, m1, m2, olen, nlen;
793: int save;
794:
795: if (old == new)
796: return;
797:
798: /* Mark physical screen as containing the line `new' */
799: PhysScreen[vpos + 1] = new;
800:
801: if ((new && new->highlighted) != (old && old->highlighted))
802: {
803: change_line_highlight (new && new->highlighted, vpos, old ? old->length : 0);
804: old = 0;
805: }
806: else
807: reassert_line_highlight (new && new->highlighted, vpos);
808:
809: if (!old)
810: {
811: olen = 0;
812: }
813: else
814: {
815: obody = old -> body;
816: olen = old->length;
817: if (! old->highlighted)
818: {
819: /* Note obody[-1] is old->physical, which is always 0 or 1. */
820: if (!must_write_spaces)
821: while (obody[olen - 1] == ' ')
822: olen--;
823: }
824: else
825: {
826: /* For an inverse-video line, remember we gave it
827: spaces all the way to the screen edge
828: so that the reverse video extends all the way across. */
829: while (olen < screen_width - 1)
830: obody[olen++] = ' ';
831: }
832: }
833:
834: if (!new)
835: {
836: nlen = 0;
837: goto just_erase;
838: }
839:
840: nbody = new -> body;
841: nlen = new->length;
842:
843: /* Pretend trailing spaces are not there at all,
844: unless for one reason or another we must write all spaces. */
845: /* We know that the previous character is the `physical' field
846: and it is zero or one. */
847: if (! new->highlighted)
848: {
849: if (!must_write_spaces)
850: while (nbody[nlen - 1] == ' ')
851: nlen--;
852: }
853: else
854: {
855: /* For an inverse-video line, give it extra trailing spaces
856: all the way to the screen edge
857: so that the reverse video extends all the way across. */
858: while (nlen < screen_width - 1)
859: nbody[nlen++] = ' ';
860: }
861:
862: /* If there's no i/d char, quickly do the best we can without it. */
863: if (!char_ins_del_ok)
864: {
865: int i,j;
866:
867: for (i = 0; i < nlen; i++)
868: {
869: if (i >= olen || nbody[i] != obody[i])
870: {
871: /* We found a non-matching char. */
872: topos (vpos, i);
873: for (j = 1; (i + j < nlen &&
874: (i + j >= olen || nbody[i+j] != obody[i+j]));
875: j++);
876: /* Output this run of non-matching chars. */
877: write_chars (nbody + i, j);
878: i += j - 1;
879: /* Now find the next non-match. */
880: }
881: }
882: /* Clear the rest of the line, or the non-clear part of it. */
883: if (olen > nlen)
884: {
885: topos (vpos, nlen);
886: clear_end_of_line (olen);
887: }
888: return;
889: }
890:
891: if (!olen)
892: {
893: nsp = (must_write_spaces || new->highlighted)
894: ? 0 : count_blanks (nbody);
895: if (nlen > nsp)
896: {
897: topos (vpos, nsp);
898: write_chars (nbody + nsp, nlen - nsp);
899: }
900: return;
901: }
902:
903: obody[olen] = 1;
904: save = nbody[nlen];
905: nbody[nlen] = 0;
906:
907: /* Compute number of leading blanks in old and new contents. */
908: osp = count_blanks (obody);
909: if (!new->highlighted)
910: nsp = count_blanks (nbody);
911: else
912: nsp = 0;
913:
914: /* Compute number of matching chars starting with first nonblank. */
915: m1 = count_match (obody + osp, nbody + nsp);
916:
917: /* Spaces in new match implicit space past the end of old. */
918: /* A bug causing this to be a no-op was fixed in 18.29. */
919: if (!must_write_spaces && osp + m1 == olen)
920: {
921: np1 = nbody + nsp;
922: while (np1[m1] == ' ')
923: m1++;
924: }
925:
926: /* Avoid doing insert/delete char
927: just cause number of leading spaces differs
928: when the following text does not match. */
929: if (m1 == 0 && osp != nsp)
930: osp = nsp = min (osp, nsp);
931:
932: /* Find matching characters at end of line */
933: op1 = obody + olen;
934: np1 = nbody + nlen;
935: op2 = op1 + m1 - min (olen - osp, nlen - nsp);
936: while (op1 > op2 && op1[-1] == np1[-1])
937: {
938: op1--;
939: np1--;
940: }
941: m2 = obody + olen - op1;
942:
943: /* Put correct value back in nbody[nlen].
944: This is important because direct_output_for_insert
945: can write into the line at a later point. */
946: nbody[nlen] = save;
947:
948: /* tem gets the distance to insert or delete.
949: m2 is how many characters we save by doing so.
950: Is it worth it? */
951:
952: tem = (nlen - nsp) - (olen - osp);
953: if (m2 && tem && m2 <= DCICcost[tem])
954: m2 = 0;
955:
956: /* nsp - osp is the distance to insert or delete.
957: m1 + m2 is how much we save by doing so.
958: Is it worth it? */
959:
960: if (m1 + m2 && nsp != osp && m1 + m2 <= DCICcost[nsp - osp])
961: {
962: m1 = 0;
963: m2 = 0;
964: osp = nsp = min (osp, nsp);
965: }
966:
967: /* Now go through the line, inserting, writing and deleting as appropriate. */
968:
969: if (osp > nsp)
970: {
971: topos (vpos, nsp);
972: delete_chars (osp - nsp);
973: }
974: else if (nsp > osp)
975: {
976: /* If going to delete chars later in line
977: and insert earlier in the line,
978: must delete first to avoid losing data in the insert */
979: if (m2 && nlen < olen + nsp - osp)
980: {
981: topos (vpos, nlen - m2 + osp - nsp);
982: delete_chars (olen + nsp - osp - nlen);
983: olen = nlen - (nsp - osp);
984: }
985: topos (vpos, osp);
986: insert_chars ((char *)0, nsp - osp);
987: }
988: olen += nsp - osp;
989:
990: tem = nsp + m1 + m2;
991: if (nlen != tem || olen != tem)
992: {
993: topos (vpos, nsp + m1);
994: if (!m2 || nlen == olen)
995: {
996: /* If new text being written reaches right margin,
997: there is no need to do clear-to-eol at the end.
998: (and it would not be safe, since cursor is not
999: going to be "at the margin" after the text is done) */
1000: if (nlen == screen_width)
1001: olen = 0;
1002: write_chars (nbody + nsp + m1, nlen - tem);
1003: #ifdef obsolete
1004: /* the following code loses disastrously if tem == nlen.
1005: Rather than trying to fix that case, I am trying the simpler
1006: solution found above. */
1007: /* If the text reaches to the right margin,
1008: it will lose one way or another (depending on AutoWrap)
1009: to clear to end of line after outputting all the text.
1010: So pause with one character to go and clear the line then. */
1011: if (nlen == screen_width && fast_clear_end_of_line && olen > nlen)
1012: {
1013: /* m2 must be zero, and tem must equal nsp + m1 */
1014: write_chars (nbody + tem, nlen - tem - 1);
1015: clear_end_of_line (olen);
1016: olen = 0; /* Don't let it be cleared again later */
1017: write_chars (nbody + nlen - 1, 1);
1018: }
1019: else
1020: write_chars (nbody + nsp + m1, nlen - tem);
1021: #endif
1022: }
1023: else if (nlen > olen)
1024: {
1025: write_chars (nbody + nsp + m1, olen - tem);
1026: insert_chars (nbody + nsp + m1 + olen - tem, nlen - olen);
1027: olen = nlen;
1028: }
1029: else if (olen > nlen)
1030: {
1031: write_chars (nbody + nsp + m1, nlen - tem);
1032: delete_chars (olen - nlen);
1033: olen = nlen;
1034: }
1035: }
1036:
1037: just_erase:
1038: /* If any unerased characters remain after the new line, erase them. */
1039: if (olen > nlen)
1040: {
1041: topos (vpos, nlen);
1042: clear_end_of_line (olen);
1043: }
1044: }
1045:
1046: count_blanks (str)
1047: char *str;
1048: {
1049: register char *p = str;
1050: while (*str++ == ' ');
1051: return str - p - 1;
1052: }
1053:
1054: count_match (str1, str2)
1055: char *str1, *str2;
1056: {
1057: register char *p1 = str1;
1058: register char *p2 = str2;
1059: while (*p1++ == *p2++);
1060: return p1 - str1 - 1;
1061: }
1062:
1063: DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript,
1064: 1, 1, "FOpen termscript file: ",
1065: "Start writing all terminal output to FILE as well as the terminal.\n\
1066: FILE = nil means just close any termscript file currently open.")
1067: (file)
1068: Lisp_Object file;
1069: {
1070: if (termscript != 0) fclose (termscript);
1071: termscript = 0;
1072:
1073: if (! NULL (file))
1074: {
1075: file = Fexpand_file_name (file, Qnil);
1076: termscript = fopen (XSTRING (file)->data, "w");
1077: if (termscript == 0)
1078: report_file_error ("Opening termscript", Fcons (file, Qnil));
1079: }
1080: return Qnil;
1081: }
1082:
1083: DEFUN ("set-screen-height", Fset_screen_height, Sset_screen_height, 1, 2, 0,
1084: "Tell redisplay that the screen has LINES lines.\n\
1085: Optional second arg non-nil means that redisplay should use LINES lines\n\
1086: but that the idea of the actual height of the screen should not be changed.")
1087: (n, pretend)
1088: Lisp_Object n, pretend;
1089: {
1090: CHECK_NUMBER (n, 0);
1091: change_screen_size (XINT (n), 0, !NULL (pretend));
1092: return Qnil;
1093: }
1094:
1095: DEFUN ("set-screen-width", Fset_screen_width, Sset_screen_width, 1, 2, 0,
1096: "Tell redisplay that the screen has COLS columns.\n\
1097: Optional second arg non-nil means that redisplay should use COLS columns\n\
1098: but that the idea of the actual width of the screen should not be changed.")
1099: (n, pretend)
1100: Lisp_Object n, pretend;
1101: {
1102: CHECK_NUMBER (n, 0);
1103: change_screen_size (0, XINT (n), !NULL (pretend));
1104: return Qnil;
1105: }
1106:
1107: DEFUN ("screen-height", Fscreen_height, Sscreen_height, 0, 0, 0,
1108: "Return number of lines on screen available for display.")
1109: ()
1110: {
1111: return make_number (screen_height);
1112: }
1113:
1114: DEFUN ("screen-width", Fscreen_width, Sscreen_width, 0, 0, 0,
1115: "Return number of columns on screen available for display.")
1116: ()
1117: {
1118: return make_number (screen_width);
1119: }
1120:
1121: #ifdef SIGWINCH
1122: window_change_signal ()
1123: {
1124: int width, height;
1125: extern int errno;
1126: int old_errno = errno;
1127:
1128: get_screen_size (&width, &height);
1129: change_screen_size (height, width, 0);
1130: signal (SIGWINCH, window_change_signal);
1131:
1132: errno = old_errno;
1133: }
1134: #endif /* SIGWINCH */
1135:
1136: /* Prevent screen size from being changed by signals. */
1137: hold_window_change ()
1138: {
1139: in_display = 1;
1140: }
1141:
1142: /* Reenable signals to change the screen size
1143: and handle any signals that have happened already. */
1144:
1145: unhold_window_change ()
1146: {
1147: in_display = 0;
1148: /* If change_screen_size should have run before, run it now. */
1149: while (delayed_size_change)
1150: {
1151: int newwidth = delayed_screen_width;
1152: int newheight = delayed_screen_height;
1153: delayed_size_change = 0;
1154: in_display = 1;
1155: change_screen_size_1 (newheight, newwidth, 0);
1156: in_display = 0;
1157: }
1158: }
1159:
1160: /* Change the screen height and/or width. Values may be given as zero to
1161: indicate no change is to take place.
1162: PRETEND is normally 0; 1 means change used-size only
1163: but don't change the size used for calculations;
1164: -1 means don't redisplay. */
1165:
1166: change_screen_size (newlength, newwidth, pretend)
1167: register int newlength, newwidth, pretend;
1168: {
1169: /* If we can't deal with the change now, queue it for later. */
1170: if (in_display)
1171: {
1172: delayed_screen_width = newwidth;
1173: delayed_screen_height = newlength;
1174: delayed_size_change = 1;
1175: return;
1176: }
1177: delayed_size_change = 0;
1178: change_screen_size_1 (newlength, newwidth, pretend);
1179: }
1180:
1181: change_screen_size_1 (newlength, newwidth, pretend)
1182: register int newlength, newwidth, pretend;
1183: {
1184: if ((newlength == 0 || newlength == screen_height)
1185: && (newwidth == 0 || newwidth == screen_width))
1186: return;
1187: if (newlength && newlength != screen_height)
1188: {
1189: if (newlength > MScreenLength)
1190: newlength = MScreenLength;
1191: set_window_height (XWINDOW (minibuf_window)->prev, newlength - 1, 0);
1192: XFASTINT (XWINDOW (minibuf_window)->top) = newlength - 1;
1193: set_window_height (minibuf_window, 1, 0);
1194: screen_height = newlength;
1195: if (pretend <= 0)
1196: ScreenRows = newlength;
1197: set_terminal_window (0);
1198: }
1199: if (newwidth && newwidth != screen_width)
1200: {
1201: if (newwidth > MScreenWidth)
1202: newwidth = MScreenWidth;
1203: set_window_width (XWINDOW (minibuf_window)->prev, newwidth, 0);
1204: set_window_width (minibuf_window, newwidth, 0);
1205: screen_width = newwidth;
1206: if (pretend <= 0)
1207: ScreenCols = newwidth;
1208: }
1209: make_display_lines ();
1210: calculate_costs ();
1211: if (pretend >= 0)
1212: DoDsp (1);
1213: }
1214:
1215: DEFSIMPLE ("baud-rate", Fbaud_rate, Sbaud_rate,
1216: "Return the output baud rate of the terminal.",
1217: Lisp_Int, XSETINT, baud_rate)
1218:
1219: DEFUN ("send-string-to-terminal", Fsend_string_to_terminal,
1220: Ssend_string_to_terminal, 1, 1, 0,
1221: "Send STRING to the terminal without alteration.\n\
1222: Control characters in STRING will have terminal-dependent effects.")
1223: (str)
1224: Lisp_Object str;
1225: {
1226: CHECK_STRING (str, 0);
1227: fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, stdout);
1228: fflush (stdout);
1229: if (termscript)
1230: {
1231: fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, termscript);
1232: fflush (termscript);
1233: }
1234: return Qnil;
1235: }
1236:
1237: DEFUN ("ding", Fding, Sding, 0, 1, 0,
1238: "Beep, or flash the screen.\n\
1239: Terminates any keyboard macro currently executing unless an argument\n\
1240: is given.")
1241: (arg)
1242: Lisp_Object arg;
1243: {
1244: if (!NULL (arg))
1245: {
1246: ring_bell ();
1247: fflush (stdout);
1248: }
1249: else
1250: Ding ();
1251: return Qnil;
1252: }
1253:
1254: Ding ()
1255: {
1256: if (noninteractive)
1257: putchar (07);
1258: else if (!INTERACTIVE) /* Stop executing a keyboard macro. */
1259: error ("Keyboard macro terminated by a command ringing the bell");
1260: else
1261: ring_bell ();
1262: fflush (stdout);
1263: }
1264:
1265: DEFUN ("sleep-for", Fsleep_for, Ssleep_for, 1, 1, 0,
1266: "Pause, without updating display, for ARG seconds.")
1267: (n)
1268: Lisp_Object n;
1269: {
1270: register int t;
1271: #ifndef subprocesses
1272: #ifdef HAVE_TIMEVAL
1273: struct timeval timeout, end_time, garbage1;
1274: #endif /* HAVE_TIMEVAL */
1275: #endif /* no subprocesses */
1276:
1277: CHECK_NUMBER (n, 0);
1278: t = XINT (n);
1279: if (t <= 0)
1280: return Qnil;
1281:
1282: #ifdef subprocesses
1283: wait_reading_process_input (t, 0, 0);
1284: #else /* No subprocesses */
1285: immediate_quit = 1;
1286: QUIT;
1287:
1288: #ifdef VMS
1289: sys_sleep (t);
1290: #else /* not VMS */
1291: /* The reason this is done this way
1292: (rather than defined (H_S) && defined (H_T))
1293: is because the VMS preprocessor doesn't grok `defined' */
1294: #ifdef HAVE_SELECT
1295: #ifdef HAVE_TIMEVAL
1296: gettimeofday (&end_time, &garbage1);
1297: end_time.tv_sec += t;
1298:
1299: while (1)
1300: {
1301: gettimeofday (&timeout, &garbage1);
1302: timeout.tv_sec = end_time.tv_sec - timeout.tv_sec;
1303: timeout.tv_usec = end_time.tv_usec - timeout.tv_usec;
1304: if (timeout.tv_usec < 0)
1305: timeout.tv_usec += 1000000,
1306: timeout.tv_sec--;
1307: if (timeout.tv_sec < 0)
1308: break;
1309: if (!select (1, 0, 0, 0, &timeout))
1310: break;
1311: }
1312: #else /* not HAVE_TIMEVAL */
1313: /* Is it safe to quit out of `sleep'? I'm afraid to trust it. */
1314: sleep (t);
1315: #endif /* HAVE_TIMEVAL */
1316: #else /* not HAVE_SELECT */
1317: sleep (t);
1318: #endif /* HAVE_SELECT */
1319: #endif /* not VMS */
1320:
1321: immediate_quit = 0;
1322: #endif /* no subprocesses */
1323: return Qnil;
1324: }
1325:
1326: DEFUN ("sit-for", Fsit_for, Ssit_for, 1, 2, 0,
1327: "Perform redisplay, then wait for ARG seconds or until input is available.\n\
1328: Optional second arg non-nil means don't redisplay.\n\
1329: Redisplay is preempted as always if input arrives, and does not happen\n\
1330: if input is available before it starts.\n\
1331: Value is t if waited the full time with no input arriving.")
1332: (n, nodisp)
1333: Lisp_Object n, nodisp;
1334: {
1335: #ifndef subprocesses
1336: #ifdef HAVE_TIMEVAL
1337: struct timeval timeout;
1338: #else
1339: int timeout_sec;
1340: #endif
1341: int waitchannels;
1342: #endif /* no subprocesses */
1343:
1344: CHECK_NUMBER (n, 0);
1345:
1346: if (detect_input_pending ())
1347: return Qnil;
1348:
1349: if (EQ (nodisp, Qnil))
1350: DoDsp (1); /* Make the screen correct */
1351: if (XINT (n) > 0)
1352: {
1353: #ifdef subprocesses
1354: #ifdef SIGIO
1355: gobble_input ();
1356: #endif /* SIGIO */
1357: wait_reading_process_input (XINT (n), 1, 1);
1358: #else /* no subprocesses */
1359: immediate_quit = 1;
1360: QUIT;
1361:
1362: waitchannels = 1;
1363: #ifdef VMS
1364: input_wait_timeout (XINT (n));
1365: #else /* not VMS */
1366: #ifndef HAVE_TIMEVAL
1367: timeout_sec = XINT (n);
1368: select (1, &waitchannels, 0, 0, &timeout_sec);
1369: #else /* HAVE_TIMEVAL */
1370: timeout.tv_sec = XINT (n);
1371: timeout.tv_usec = 0;
1372: select (1, &waitchannels, 0, 0, &timeout);
1373: #endif /* HAVE_TIMEVAL */
1374: #endif /* not VMS */
1375:
1376: immediate_quit = 0;
1377: #endif /* no subprocesses */
1378: }
1379: return detect_input_pending () ? Qnil : Qt;
1380: }
1381:
1382: char *terminal_type;
1383:
1384: /* Initialization done when Emacs fork is started, before doing stty. */
1385: /* Determine terminal type and set terminal_driver */
1386: /* Then invoke its decoding routine to set up variables
1387: in the terminal package */
1388:
1389: init_display ()
1390: {
1391: #ifdef HAVE_X_WINDOWS
1392: extern Lisp_Object Vxterm;
1393: Vxterm = Qnil;
1394: #endif
1395:
1396: Vwindow_system = Qnil;
1397: MetaFlag = 0;
1398: inverse_video = 0;
1399: cursor_in_echo_area = 0;
1400: terminal_type = (char *) 0;
1401:
1402: if (!inhibit_window_system)
1403: {
1404: #ifdef HAVE_X_WINDOWS
1405: extern char *alternate_display;
1406: char *disp = egetenv ("DISPLAY");
1407:
1408: /* Note KSH likes to provide an empty string as an envvar value. */
1409: if (alternate_display || (disp && *disp))
1410: {
1411: x_term_init ();
1412: Vxterm = Qt;
1413: Vwindow_system = intern ("x");
1414: #ifdef X11
1415: Vwindow_system_version = make_number (11);
1416: #else
1417: Vwindow_system_version = make_number (10);
1418: #endif
1419: goto term_init_done;
1420: }
1421: #endif /* HAVE_X_WINDOWS */
1422: ;
1423: }
1424: /* Record we aren't using a window system. */
1425: inhibit_window_system = 1;
1426:
1427: /* Look at the TERM variable */
1428: terminal_type = (char *) getenv ("TERM");
1429: if (!terminal_type)
1430: {
1431: #ifdef VMS
1432: fprintf (stderr, "Please specify your terminal type.\n\
1433: For types defined in VMS, use set term /device=TYPE.\n\
1434: For types not defined in VMS, use define emacs_term \"TYPE\".\n\
1435: \(The quotation marks are necessary since terminal types are lower case.)\n");
1436: #else
1437: fprintf (stderr, "Please set the environment variable TERM; see tset(1).\n");
1438: #endif
1439: exit (1);
1440: }
1441: term_init (terminal_type);
1442:
1443: term_init_done:
1444: make_display_lines ();
1445:
1446: cursX = 0; /* X and Y coordinates of the cursor */
1447: cursY = 0; /* between updates. */
1448:
1449: #ifdef SIGWINCH
1450: #ifndef CANNOT_DUMP
1451: if (initialized)
1452: #endif /* CANNOT_DUMP */
1453: if (inhibit_window_system)
1454: signal (SIGWINCH, window_change_signal);
1455: #endif /* SIGWINCH */
1456: }
1457:
1458: syms_of_display ()
1459: {
1460: defsubr (&Sopen_termscript);
1461: defsubr (&Sding);
1462: defsubr (&Ssit_for);
1463: defsubr (&Sscreen_height);
1464: defsubr (&Sscreen_width);
1465: defsubr (&Sset_screen_height);
1466: defsubr (&Sset_screen_width);
1467: defsubr (&Ssleep_for);
1468: defsubr (&Sbaud_rate);
1469: defsubr (&Ssend_string_to_terminal);
1470:
1471: DEFVAR_BOOL ("inverse-video", &inverse_video,
1472: "*Non-nil means use inverse-video.");
1473: DEFVAR_BOOL ("visible-bell", &visible_bell,
1474: "*Non-nil means try to flash the screen to represent a bell.");
1475: DEFVAR_BOOL ("no-redraw-on-reenter", &no_redraw_on_reenter,
1476: "*Non-nil means no need to redraw entire screen after suspending.\n\
1477: It is up to you to set this variable to inform Emacs.");
1478: DEFVAR_LISP ("window-system", &Vwindow_system,
1479: "A symbol naming the window-system under which Emacs is running,\n\
1480: \(such as `x'), or nil if emacs is running on an ordinary terminal.");
1481: DEFVAR_LISP ("window-system-version", &Vwindow_system_version,
1482: "Version number of the window system Emacs is running under.");
1483: Vwindow_system_version = Qnil;
1484: DEFVAR_BOOL ("cursor-in-echo-area", &cursor_in_echo_area,
1485: "Non-nil means put cursor in minibuffer after any message displayed there.");
1486:
1487: /* Initialize `window-system', unless init_display already decided it. */
1488: #ifdef CANNOT_DUMP
1489: if (noninteractive)
1490: #endif
1491: Vwindow_system = Qnil;
1492: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.