|
|
1.1 root 1: /* Newly written part of redisplay code.
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 <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 USG
36: #include <termio.h>
37: #else /* not USG */
38: #include <sys/ioctl.h>
39: #endif /* not USG */
40:
41: #undef NULL
42:
43: #include "termchar.h"
44: #include "termopts.h"
45: #include "cm.h"
46: #include "dispextern.h"
47: #include "lisp.h"
48: #include "buffer.h"
49: #include "window.h"
50: #include "commands.h"
51:
52: #define max(a, b) ((a) > (b) ? (a) : (b))
53: #define min(a, b) ((a) < (b) ? (a) : (b))
54:
55: /* Nonzero means do not assume anything about current
56: contents of actual terminal screen */
57:
58: int screen_garbaged;
59:
60: /* Desired terminal cursor position (to show position of point),
61: origin zero */
62:
63: int cursX, cursY;
64:
65: /* Nonzero means last display completed and cursor is really at cursX, cursY.
66: Zero means it was preempted. */
67:
68: int display_completed;
69:
70: int visible_bell; /* If true and the terminal will support it
71: then the screen will flash instead of
72: feeping when an error occurs */
73: int inverse_video; /* If true and the terminal will support it
74: then we will use inverse video */
75:
76: int baud_rate; /* Terminal speed, so we can calculate
77: the number of characters required to
78: make the cursor sit still for n secs. */
79:
80: /* the current (physical) screen */
81: struct display_line *PhysScreen[MScreenLength + 1];
82:
83: /* temporary Copy of PhysScreen made in update_screen */
84: struct display_line *OPhysScreen[MScreenLength + 1];
85:
86: /* the desired (virtual) screen */
87: struct display_line *DesiredScreen[MScreenLength + 1];
88:
89: /* Record here all the display line objects, for debugging. */
90: static struct display_line *all_lines[2 * MScreenLength];
91:
92: FILE *termscript; /* Stdio stream being used for copy of all kbdinput. */
93:
94: struct cm Wcm; /* Structure for info on cursor positioning */
95:
96: extern short ospeed; /* Output speed (from sg_ospeed) */
97:
98: /* Use these to chain together free lines */
99:
100: #define LINE_NEXT(l) (*(struct display_line **) l)
101: #define SET_LINE_NEXT(l, next) (*((struct display_line **) l) = next)
102:
103: /* Chain of free display_line structures, chained thru LINE_NEXT. */
104:
105: struct display_line *free_display_lines;
106:
107: /* Number of lines now free. */
108:
109: int free_line_count;
110:
111: /* Allocate as many display_line structures
112: as we are ever supposed to need.
113: Called at startup, and also if screen size is changed. */
114:
115: make_display_lines ()
116: {
117: register int i;
118: register struct display_line *p, *p1;
119:
120: /* First, free any that are already allocated */
121:
122: for (p = free_display_lines; p;)
123: {
124: p1 = p;
125: p = LINE_NEXT (p);
126: free (p1);
127: }
128: free_display_lines = 0;
129: free_line_count = 0;
130:
131: for (i = 0; i <= MScreenLength; i++)
132: if (PhysScreen[i])
133: {
134: free (PhysScreen[i]);
135: PhysScreen[i] = 0;
136: }
137:
138: screen_garbaged = 1;
139:
140: /* Now allocate as many as we can possibly validly need */
141:
142: for (i = - screen_height; i < screen_height; i++)
143: {
144: p = (struct display_line *) malloc (sizeof (struct display_line) + screen_width - MScreenWidth);
145: if (!p) abort ();
146: SET_LINE_NEXT (p, free_display_lines);
147: free_display_lines = p;
148: all_lines[i + screen_height] = p;
149: }
150: free_line_count = 2 * screen_height;
151: }
152:
153: /* Get one of the previously malloc'd display_line structures
154: from the free pool. */
155:
156: struct display_line *
157: new_display_line ()
158: {
159: register struct display_line *p = free_display_lines;
160: /* If we ever use up all the display lines that have been
161: allocated, it indicates a bug, since we are supposed
162: to need at most two for each line on the screen. */
163: if (!p)
164: abort ();
165: free_display_lines = LINE_NEXT (p);
166:
167: bzero (p, p->body - (char *) p);
168: SET_LINE_NEXT (p, (struct display_line *)1); /* Mark as in use. */
169: free_line_count--;
170: return p;
171: }
172:
173: /* Put a display_line back in the free pool. */
174:
175: return_display_line (p)
176: struct display_line *p;
177: {
178: if (!p)
179: return;
180: if ((int) LINE_NEXT (p) != 1)
181: abort (); /* Already free. */
182: SET_LINE_NEXT (p, free_display_lines);
183: free_display_lines = p;
184: free_line_count++;
185: }
186:
187: clear_screen_records ()
188: {
189: register int i;
190: for (i = 1; i <= screen_height; i++)
191: if (PhysScreen[i])
192: return_display_line (PhysScreen[i]);
193: bzero (PhysScreen, (screen_height + 1) * sizeof PhysScreen[0]);
194: }
195:
196: /* Return the hash code of display_line p. */
197: line_hash_code (p)
198: register struct display_line *p;
199: {
200: register char *body, *end;
201: register int h = 0;
202: if (!p)
203: return 0;
204: /* Give all lighlighted lines the same hash code
205: so as to encourage scrolling to leave them in place. */
206: if (p->highlighted)
207: return -1;
208:
209: body = p->body;
210: end = body + p->length;
211: *end = 0;
212: if (!must_write_spaces)
213: {
214: while (*body++ == ' ');
215: body--;
216: if (body == end)
217: return 1;
218: while (end[-1] == ' ') end--;
219: }
220: while (body != end)
221: h = (h << 5) + h + *body++;
222: if (h)
223: return h;
224: return 1;
225: }
226:
227: /* Return number of characters in display_line p,
228: except don't count leading and trailing spaces
229: unless the terminal requires those to be explicitly output. */
230:
231: line_draw_cost (p)
232: struct display_line *p;
233: {
234: register char *body;
235: register int i;
236:
237: if (!p)
238: return 0;
239:
240: if (must_write_spaces)
241: return p->length;
242:
243: body = p->body - 1;
244: for (i = p->length; i > 0 && body[i - 1] == ' '; i--);
245:
246: i -= count_blanks (p->body);
247: return max (i, 0);
248: }
249:
250: /* The functions on this page are the interface from xdisp.c to redisplay.
251: They take cursor position arguments in origin 0.
252:
253: The only other interface into redisplay is through setting
254: cursX and cursY (in xdisp.c) and setting screen_garbaged. */
255:
256: /* cancel_line eliminates any request to display a line at position `vpos' */
257:
258: cancel_line (vpos)
259: int vpos;
260: {
261: return_display_line (DesiredScreen[vpos + 1]);
262: DesiredScreen[vpos + 1] = 0;
263: }
264:
265: /* Get a display_line for displaying on line `vpos'
266: and set it up for outputting starting at `hpos' within it. */
267:
268: struct display_line *
269: get_display_line (vpos, hpos)
270: int vpos;
271: register int hpos;
272: {
273: register struct display_line *line;
274: register char *p;
275:
276: if (vpos < 0) abort ();
277:
278: line = DesiredScreen[vpos + 1];
279: if (line && line->length > hpos)
280: abort ();
281: if (!line)
282: line = new_display_line ();
283:
284: if (hpos > line->length)
285: {
286: p = line->body + line->length;
287: hpos -= line->length;
288: line->length += hpos;
289: while (--hpos >= 0)
290: *p++ = ' ';
291: }
292:
293: DesiredScreen[vpos + 1] = line;
294:
295: return line;
296: }
297:
298: /* Scroll lines from vpos `from' up to but not including vpos `end'
299: down by `amount' lines (`amount' may be negative).
300: Returns nonzero if done, zero if terminal cannot scroll them. */
301:
302: int
303: scroll_screen_lines (from, end, amount)
304: int from, end, amount;
305: {
306: register int i;
307:
308: if (!line_ins_del_ok)
309: return 0;
310:
311: if (amount == 0)
312: return 1;
313: if (amount > 0)
314: {
315: set_terminal_window (end + amount);
316: if (!scroll_region_ok)
317: ins_del_lines (end, -amount);
318: ins_del_lines (from, amount);
319: set_terminal_window (0);
320:
321: for (i = end + amount; i >= end + 1; i--)
322: return_display_line (PhysScreen[i]);
323: for (i = end; i >= from + 1; i--)
324: PhysScreen[i + amount] = PhysScreen[i];
325: for (i = from + amount; i >= from + 1; i--)
326: PhysScreen[i] = 0;
327: }
328: if (amount < 0)
329: {
330: set_terminal_window (end);
331: ins_del_lines (from + amount, amount);
332: if (!scroll_region_ok)
333: ins_del_lines (end + amount, -amount);
334: set_terminal_window (0);
335:
336: for (i = from + amount + 1; i <= from; i++)
337: return_display_line (PhysScreen[i]);
338: for (i = from + 1; i <= end ; i++)
339: PhysScreen[i + amount] = PhysScreen[i];
340: for (i = end + amount + 1; i <= end; i++)
341: PhysScreen[i] = 0;
342: }
343: return 1;
344: }
345:
346: /* After updating a window w that isn't the full screen wide,
347: copy all the columns that w does not occupy
348: into the DesiredScreen lines from the PhysScreen lines
349: so that update_screen will not change those columns. */
350:
351: preserve_other_columns (w)
352: struct window *w;
353: {
354: register int vpos;
355: register struct display_line *l1, *l2;
356: int start = XFASTINT (w->left);
357: int end = XFASTINT (w->left) + XFASTINT (w->width);
358: int bot = XFASTINT (w->top) + XFASTINT (w->height);
359:
360: for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
361: {
362: if ((l1 = DesiredScreen[vpos + 1])
363: && (l2 = PhysScreen[vpos + 1]))
364: {
365: if (start > 0)
366: {
367: bcopy (l2->body, l1->body, start);
368: if (l1->length < start && l1->length < l2->length)
369: l1->length = min (start, l2->length);
370: }
371: if (l2->length > end && l1->length < l2->length)
372: {
373: while (l1->length < end)
374: l1->body[l1->length++] = ' ';
375: bcopy (l2->body + end, l1->body + end, l2->length - end);
376: l1->length = l2->length;
377: }
378: }
379: }
380: }
381:
382: #ifdef NOTDEF
383:
384: /* If window w does not need to be updated and isn't the full screen wide,
385: copy all the columns that w does occupy
386: into the DesiredScreen lines from the PhysScreen lines
387: so that update_screen will not change those columns.
388:
389: Have not been able to figure out how to use this correctly. */
390:
391: preserve_my_columns (w)
392: struct window *w;
393: {
394: register int vpos, fin;
395: register struct display_line *l1, *l2;
396: int start = XFASTINT (w->left);
397: int end = XFASTINT (w->left) + XFASTINT (w->width);
398: int bot = XFASTINT (w->top) + XFASTINT (w->height);
399:
400: for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
401: {
402: if ((l1 = DesiredScreen[vpos + 1])
403: && (l2 = PhysScreen[vpos + 1]))
404: {
405: if (l2->length > start && l1->length < l2->length)
406: {
407: fin = l2->length;
408: if (fin > end) fin = end;
409: while (l1->length < start)
410: l1->body[l1->length++] = ' ';
411: bcopy (l2->body + start, l1->body + start, fin - start);
412: l1->length = fin;
413: }
414: }
415: }
416: }
417:
418: #endif /* NOTDEF */
419:
420: /* On discovering that the redisplay for a window was no good,
421: cancel the columns of that window,
422: so that when the window is displayed over again
423: get_display_line will not complain. */
424:
425: cancel_my_columns (w)
426: struct window *w;
427: {
428: register int vpos;
429: register struct display_line *l;
430: register int start = XFASTINT (w->left);
431: register int bot = XFASTINT (w->top) + XFASTINT (w->height);
432:
433: for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
434: {
435: if ((l = DesiredScreen[vpos + 1])
436: && l->length >= start)
437: l->length = start;
438: }
439: }
440:
441: direct_output_for_insert (c)
442: int c;
443: {
444: register struct display_line *p = PhysScreen[cursY + 1];
445: #ifndef COMPILER_REGISTER_BUG
446: register
447: #endif COMPILER_REGISTER_BUG
448: struct window *w = XWINDOW (selected_window);
449: #ifndef COMPILER_REGISTER_BUG
450: register
451: #endif COMPILER_REGISTER_BUG
452: int hpos = cursX;
453:
454: /* Give up if about to continue line */
455: if (hpos - XFASTINT (w->left) + 1 + 1 >= XFASTINT (w->width))
456: return;
457:
458: /* Avoid losing if cursor is in invisible text off left margin */
459: if (XINT (w->hscroll) && hpos == XFASTINT (w->left))
460: return;
461:
462: /* Give up if cursor outside window (in minibuf, probably) */
463: if (cursY < XFASTINT (w->top)
464: || cursY >= XFASTINT (w->top) + XFASTINT (w->height))
465: return;
466:
467: /* Give up if cursor not really at cursX, cursY */
468: if (!display_completed)
469: return;
470:
471: /* Give up if w is minibuffer and a message is being displayed there */
472: if (EQ (selected_window, minibuf_window) && minibuf_message)
473: return;
474:
475: p->body[hpos] = c;
476: unchanged_modified = bf_modified;
477: beg_unchanged = bf_s1;
478: XFASTINT (w->last_point) = point;
479: XFASTINT (w->last_point_x) = cursX;
480: XFASTINT (w->last_modified) = bf_modified;
481:
482: reassert_line_highlight (0, cursY);
483: write_chars (p->body + hpos, 1);
484: fflush (stdout);
485: ++cursX;
486: p->length = max (p->length, cursX);
487: p->body[p->length] = 0;
488: }
489:
490: direct_output_forward_char (n)
491: int n;
492: {
493: register struct window *w = XWINDOW (selected_window);
494:
495: /* Avoid losing if cursor is in invisible text off left margin */
496: if (XINT (w->hscroll) && cursX == XFASTINT (w->left))
497: return;
498:
499: cursX += n;
500: XFASTINT (w->last_point_x) = cursX;
501: XFASTINT (w->last_point) = point;
502: topos (cursY, cursX);
503: fflush (stdout);
504: }
505:
506: /* At the time this function is called,
507: no line is common to PhysScreen and DesiredScreen.
508: That is true again when this function returns. */
509:
510: /* `force' nonzero means do not stop for pending input */
511:
512: /* Value is nonzero if redisplay stopped due to pending input */
513: update_screen (force, inhibit_hairy_id)
514: int force;
515: int inhibit_hairy_id;
516: {
517: register struct display_line **p;
518: register struct display_line *l, *lnew;
519: register int i;
520: int pause;
521: int preempt_count;
522: int outq;
523: extern input_pending;
524:
525: if (screen_height == 0) abort (); /* Some bug zeros some core */
526:
527: bcopy (PhysScreen, OPhysScreen, sizeof PhysScreen);
528:
529: detect_input_pending ();
530: if (input_pending && !force)
531: {
532: pause = 1;
533: goto do_pause;
534: }
535:
536: update_begin ();
537:
538: if (!line_ins_del_ok)
539: inhibit_hairy_id = 1;
540:
541: /* Don't compute for i/d line if just want cursor motion. */
542: for (p = &DesiredScreen[screen_height]; p != DesiredScreen && *p == 0; p--);
543:
544: /* Try doing i/d line, if not yet inhibited. */
545: if (!inhibit_hairy_id && p != DesiredScreen)
546: force |= scrolling ();
547:
548: /* Update the individual lines as needed. Do bottom line first. */
549:
550: l = DesiredScreen[screen_height];
551: if (l && l != PhysScreen[screen_height])
552: update_line (PhysScreen[screen_height], l, screen_height - 1);
553: preempt_count = baud_rate / 2400;
554: for (i = 1; i < screen_height && (force || !input_pending); i++)
555: {
556: l = PhysScreen[i];
557: lnew = DesiredScreen[i];
558: if (lnew && lnew != l)
559: {
560: /* Flush out every so many lines.
561: Also flush out if likely to have more than 1k buffered otherwise.
562: I'm told that telnet connections get really screwed by more
563: than 1k output at once. */
564: outq = stdout->_ptr - stdout->_base;
565: if (outq > ((--preempt_count < 0) ? 20 : 900))
566: {
567: fflush (stdout);
568: if (baud_rate < 2400)
569: {
570: #ifdef TIOCOUTQ
571: if (ioctl (0, TIOCOUTQ, &outq) < 0)
572: /* Probably not a tty. Ignore the error and reset
573: * the outq count. */
574: outq = stdout->_ptr - stdout->_base;
575: #endif
576: outq *= 10;
577: outq /= baud_rate; /* outq is now in seconds */
578: if (outq)
579: sleep (outq);
580: }
581: detect_input_pending ();
582:
583: preempt_count = baud_rate / 2400;
584: }
585: /* Now update this line. */
586: update_line (l, lnew, i - 1);
587: }
588: }
589: pause = (i < screen_height) ? i : 0;
590:
591: /* Now just clean up termcap drivers and set cursor, etc. */
592: if (!pause)
593: topos (cursY, max (min (cursX, screen_width - 1), 0));
594:
595: update_end ();
596:
597: if (termscript)
598: fflush (termscript);
599: fflush (stdout);
600:
601: do_pause:
602: if (screen_height == 0) abort (); /* Some bug zeros some core */
603: display_completed = !pause;
604: /* Free any lines still in desired screen but not in phys screen */
605: /* Free any lines that used to be in phys screen but are no longer */
606: for (p = &PhysScreen[screen_height]; p != PhysScreen; p--)
607: if (p[0]) p[0]->physical = 1;
608: for (p = &DesiredScreen[screen_height]; p != DesiredScreen; p--)
609: {
610: if (l = *p)
611: {
612: if (!l->physical)
613: {
614: return_display_line (l);
615: /* Prevent line in both DesiredScreen and OPhysScreen
616: from being freed twice. */
617: l->physical = 1;
618: }
619: }
620: }
621: for (p = &OPhysScreen[screen_height]; p != OPhysScreen; p--)
622: {
623: if (l = *p)
624: {
625: if (!l->physical)
626: return_display_line (l);
627: }
628: }
629: i = 0;
630: for (p = &PhysScreen[screen_height]; p != PhysScreen; p--)
631: if (p[0])
632: {
633: i++;
634: p[0]->physical = 0;
635: }
636:
637: {
638: extern int debug_end_pos;
639: if (debug_end_pos && i + free_line_count != 2 * screen_height)
640: abort ();
641: }
642:
643: bzero (OPhysScreen, (screen_height + 1) * sizeof OPhysScreen[0]);
644: bzero (DesiredScreen, (screen_height + 1) * sizeof DesiredScreen[0]);
645: return pause;
646: }
647:
648: /* Decide what insert/delete line to do, and do it */
649:
650: scrolling ()
651: {
652: int unchanged_at_top, unchanged_at_bottom;
653: int window_size;
654: int changed_lines;
655: int *old_hash = (int *) alloca (screen_height * sizeof (int));
656: int *new_hash = (int *) alloca (screen_height * sizeof (int));
657: int *draw_cost = (int *) alloca (screen_height * sizeof (int));
658: register int i;
659: int free_at_end_vpos = screen_height;
660:
661: /* Compute hash codes of all the lines.
662: Also calculate number of changed lines,
663: number of unchanged lines at the beginning,
664: and number of unchanged lines at the end. */
665:
666: changed_lines = 0;
667: unchanged_at_top = 0;
668: unchanged_at_bottom = screen_height;
669: for (i = 0; i < screen_height; i++)
670: {
671: old_hash[i] = line_hash_code (PhysScreen[i + 1]);
672: if (!DesiredScreen[i + 1])
673: DesiredScreen[i + 1] = PhysScreen[i + 1];
674: if (PhysScreen[i + 1] == DesiredScreen[i + 1])
675: new_hash[i] = old_hash[i];
676: else
677: new_hash[i] = line_hash_code (DesiredScreen[i + 1]);
678: if (old_hash[i] != new_hash[i])
679: {
680: changed_lines++;
681: unchanged_at_bottom = screen_height - i - 1;
682: }
683: else if (i == unchanged_at_top)
684: unchanged_at_top++;
685: draw_cost[i] = line_draw_cost (DesiredScreen[i + 1]);
686: }
687:
688: /* If changed lines are few, don't allow preemption, don't scroll. */
689: if (changed_lines < baud_rate / 2400 || unchanged_at_bottom == screen_height)
690: return 1;
691:
692: window_size = screen_height - unchanged_at_top - unchanged_at_bottom;
693:
694: if (scroll_region_ok)
695: free_at_end_vpos -= unchanged_at_bottom;
696: else if (memory_below_screen)
697: free_at_end_vpos = -1;
698:
699: /* If large window, fast terminal and few lines in common between
700: PhysScreen and DesiredScreen, don't bother with i/d calc. */
701: if (window_size >= 18 && baud_rate > 2400
702: && (window_size >=
703: 10 * scrolling_max_lines_saved (unchanged_at_top,
704: screen_height - unchanged_at_bottom,
705: old_hash, new_hash, draw_cost)))
706: return 0;
707:
708: scrolling_1 (window_size, unchanged_at_top, unchanged_at_bottom,
709: draw_cost + unchanged_at_top - 1,
710: old_hash + unchanged_at_top - 1,
711: new_hash + unchanged_at_top - 1,
712: free_at_end_vpos - unchanged_at_top);
713:
714: return 0;
715: }
716:
717: update_line (old, new, vpos)
718: struct display_line *old, *new;
719: int vpos;
720: {
721: register char *obody, *nbody, *op1, *op2, *np1;
722: int tem;
723: int osp, nsp, m1, m2, olen, nlen;
724: int save;
725:
726: if (old == new)
727: return;
728:
729: /* Mark physical screen as containing the line `new' */
730: PhysScreen[vpos + 1] = new;
731:
732: if ((new && new->highlighted) != (old && old->highlighted))
733: {
734: change_line_highlight (new && new->highlighted, vpos, old ? old->length : 0);
735: old = 0;
736: }
737: else
738: reassert_line_highlight (new && new->highlighted, vpos);
739:
740: if (!old)
741: {
742: olen = 0;
743: }
744: else
745: {
746: obody = old -> body;
747: olen = old->length;
748: if (!must_write_spaces)
749: while (obody[olen - 1] == ' ')
750: olen--;
751: }
752:
753: if (!new)
754: {
755: nlen = 0;
756: goto just_erase;
757: }
758:
759: nbody = new -> body;
760: nlen = new->length;
761:
762: /* We know that the previous character is the `physical' field
763: and it is zero or one. */
764: if (!must_write_spaces)
765: while (nbody[nlen - 1] == ' ')
766: nlen--;
767:
768: if (!olen)
769: {
770: nsp = (must_write_spaces || new->highlighted)
771: ? 0 : count_blanks (nbody);
772: if (nlen > nsp)
773: {
774: topos (vpos, nsp);
775: write_chars (nbody + nsp, nlen - nsp);
776: }
777: return;
778: }
779:
780: obody[olen] = 1;
781: save = nbody[nlen];
782: nbody[nlen] = 0;
783:
784: /* Compute number of leading blanks in old and new contents. */
785: osp = count_blanks (obody);
786: if (!new->highlighted)
787: nsp = count_blanks (nbody);
788: else
789: nsp = 0;
790:
791: /* Compute number of matching chars starting with first nonblank. */
792: m1 = count_match (obody + osp, nbody + nsp);
793:
794: /* Spaces in new match implicit space past the end of old. */
795: /* This isn't really doing anything; osp should be osp + m1.
796: I don't dare fix it now since maybe if it does anything
797: it will do something bad. */
798: if (!must_write_spaces && osp == olen)
799: {
800: np1 = nbody + nsp;
801: while (np1[m1] == ' ')
802: m1++;
803: }
804:
805: /* Avoid doing insert/delete char
806: just cause number of leading spaces differs
807: when the following text does not match. */
808: if (m1 == 0 && osp != nsp)
809: osp = nsp = min (osp, nsp);
810:
811: /* Find matching characters at end of line */
812: op1 = obody + olen;
813: np1 = nbody + nlen;
814: op2 = op1 + m1 - min (olen - osp, nlen - nsp);
815: while (op1 > op2 && op1[-1] == np1[-1])
816: {
817: op1--;
818: np1--;
819: }
820: m2 = obody + olen - op1;
821:
822: /* Put correct value back in nbody[nlen].
823: This is important because direct_output_for_insert
824: can write into the line at a later point. */
825: nbody[nlen] = save;
826:
827: /* tem gets the distance to insert or delete.
828: m2 is how many characters we save by doing so.
829: Is it worth it? */
830:
831: tem = (nlen - nsp) - (olen - osp);
832: if (m2 && tem && m2 <= DCICcost[tem])
833: m2 = 0;
834:
835: /* nsp - osp is the distance to insert or delete.
836: m1 + m2 is how much we save by doing so.
837: Is it worth it? */
838:
839: if (m1 + m2 && nsp != osp && m1 + m2 <= DCICcost[nsp - osp])
840: {
841: m1 = 0;
842: m2 = 0;
843: osp = nsp = min (osp, nsp);
844: }
845:
846: /* Now go through the line, inserting, writing and deleting as appropriate. */
847:
848: if (osp > nsp)
849: {
850: topos (vpos, nsp);
851: delete_chars (osp - nsp);
852: }
853: else if (nsp > osp)
854: {
855: /* If going to delete chars later in line
856: and insert earlier in the line,
857: must delete first to avoid losing data in the insert */
858: if (m2 && nlen < olen + nsp - osp)
859: {
860: topos (vpos, nlen - m2 + osp - nsp);
861: delete_chars (olen + nsp - osp - nlen);
862: olen = nlen - (nsp - osp);
863: }
864: topos (vpos, osp);
865: insert_chars ((char *)0, nsp - osp);
866: }
867: olen += nsp - osp;
868: osp = nsp;
869:
870: tem = nsp + m1 + m2;
871: if (nlen != tem || olen != tem)
872: {
873: topos (vpos, nsp + m1);
874: if (!m2 || nlen == olen)
875: {
876: /* If new text being written reaches right margin,
877: there is no need to do clear-to-eol at the end.
878: (and it would not be safe, since cursor is not
879: going to be "at the margin" after the text is done) */
880: if (nlen == screen_width)
881: olen = 0;
882: write_chars (nbody + nsp + m1, nlen - tem);
883: #ifdef obsolete
884: /* the following code loses disastrously if tem == nlen.
885: Rather than trying to fix that case, I am trying the simpler
886: solution found above. */
887: /* If the text reaches to the right margin,
888: it will lose one way or another (depending on AutoWrap)
889: to clear to end of line after outputting all the text.
890: So pause with one character to go and clear the line then. */
891: if (nlen == screen_width && fast_clear_end_of_line && olen > nlen)
892: {
893: /* m2 must be zero, and tem must equal nsp + m1 */
894: write_chars (nbody + tem, nlen - tem - 1);
895: clear_end_of_line (olen);
896: olen = 0; /* Don't let it be cleared again later */
897: write_chars (nbody + nlen - 1, 1);
898: }
899: else
900: write_chars (nbody + nsp + m1, nlen - tem);
901: #endif
902: }
903: else if (nlen > olen)
904: {
905: write_chars (nbody + nsp + m1, olen - tem);
906: insert_chars (nbody + nsp + m1 + olen - tem, nlen - olen);
907: olen = nlen;
908: }
909: else if (olen > nlen)
910: {
911: write_chars (nbody + nsp + m1, nlen - tem);
912: delete_chars (olen - nlen);
913: olen = nlen;
914: }
915: }
916:
917: just_erase:
918: /* If any unerased characters remain after the new line, erase them. */
919: if (olen > nlen)
920: {
921: topos (vpos, nlen);
922: clear_end_of_line (olen);
923: }
924: }
925:
926: count_blanks (str)
927: char *str;
928: {
929: register char *p = str;
930: while (*str++ == ' ');
931: return str - p - 1;
932: }
933:
934: count_match (str1, str2)
935: char *str1, *str2;
936: {
937: register char *p1 = str1;
938: register char *p2 = str2;
939: while (*p1++ == *p2++);
940: return p1 - str1 - 1;
941: }
942:
943: DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript,
944: 1, 1, "FOpen termscript file: ",
945: "Start writing all terminal output to FILE as well.")
946: (file)
947: Lisp_Object file;
948: {
949: file = Fexpand_file_name (file, Qnil);
950: termscript = fopen (XSTRING (file)->data, "w");
951: return Qnil;
952: }
953:
954: DEFUN ("set-screen-height", Fset_screen_height, Sset_screen_height, 1, 1, 0,
955: "Set number of lines on screen available for use in windows.")
956: (n)
957: Lisp_Object n;
958: {
959: CHECK_NUMBER (n, 0);
960: change_screen_size (XINT (n), 0);
961: return Qnil;
962: }
963:
964: DEFUN ("set-screen-width", Fset_screen_width, Sset_screen_width, 1, 1, 0,
965: "Set number of columns on screen available for display.")
966: (n)
967: Lisp_Object n;
968: {
969: CHECK_NUMBER (n, 0);
970: change_screen_size (0, XINT (n));
971: return Qnil;
972: }
973:
974: DEFUN ("screen-height", Fscreen_height, Sscreen_height, 0, 0, 0,
975: "Return number of lines on screen available for use in windows.")
976: ()
977: {
978: return make_number (screen_height);
979: }
980:
981: DEFUN ("screen-width", Fscreen_width, Sscreen_width, 0, 0, 0,
982: "Return number of columns on screen available for display.")
983: ()
984: {
985: return make_number (screen_width);
986: }
987:
988: /* Change the screen height and/or width. Values may be given as zero to
989: indicate no change is to take place. */
990: change_screen_size (newlength, newwidth)
991: register int newlength, newwidth;
992: {
993: if ((newlength == 0 || newlength == screen_height)
994: && (newwidth == 0 || newwidth == screen_width))
995: return;
996: if (newlength && newlength != screen_height)
997: {
998: if (newlength > MScreenLength)
999: newlength = MScreenLength;
1000: set_window_height (XWINDOW (minibuf_window)->prev, newlength - 1, 0);
1001: XFASTINT (XWINDOW (minibuf_window)->top) = newlength - 1;
1002: set_window_height (minibuf_window, 1, 0);
1003: screen_height = newlength;
1004: set_terminal_window (0);
1005: }
1006: if (newwidth && newwidth != screen_width)
1007: {
1008: if (newwidth > MScreenWidth)
1009: newwidth = MScreenWidth;
1010: set_window_width (XWINDOW (minibuf_window)->prev, newwidth, 0);
1011: set_window_width (minibuf_window, newwidth, 0);
1012: screen_width = newwidth;
1013: }
1014: make_display_lines ();
1015: calculate_costs ();
1016: DoDsp (1);
1017: }
1018:
1019: DEFSIMPLE ("baud-rate", Fbaud_rate, Sbaud_rate,
1020: "Return the output baud rate of the terminal.",
1021: Lisp_Int, XSETINT, baud_rate)
1022:
1023: DEFUN ("send-string-to-terminal", Fsend_string_to_terminal,
1024: Ssend_string_to_terminal, 1, 1, 0,
1025: "Send STRING to the terminal without alteration.\n\
1026: Control characters in STRING will have terminal-dependent effects.")
1027: (str)
1028: Lisp_Object str;
1029: {
1030: CHECK_STRING (str, 0);
1031: fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, stdout);
1032: fflush (stdout);
1033: if (termscript)
1034: {
1035: fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, termscript);
1036: fflush (termscript);
1037: }
1038: return Qnil;
1039: }
1040:
1041: DEFUN ("ding", Fding, Sding, 0, 0, 0,
1042: "Beep, or flash the screen.\n\
1043: Terminates any keyboard macro currently executing.")
1044: ()
1045: {
1046: Ding ();
1047: return Qnil;
1048: }
1049:
1050: Ding ()
1051: {
1052: if (noninteractive)
1053: putchar (07);
1054: else if (!INTERACTIVE) /* Stop executing a keyboard macro. */
1055: error ("Keyboard macro terminated by a command ringing the bell");
1056: else
1057: ring_bell ();
1058: fflush (stdout);
1059: }
1060:
1061: DEFUN ("sleep-for", Fsleep_for, Ssleep_for, 1, 1, 0,
1062: "Pause, without updating display, for ARG seconds.")
1063: (n)
1064: Lisp_Object n;
1065: {
1066: register int t;
1067: #ifndef subprocesses
1068: #ifdef HAVE_TIMEVAL
1069: struct timeval timeout, end_time, garbage1;
1070: #endif /* HAVE_TIMEVAL */
1071: #endif /* no subprocesses */
1072:
1073: CHECK_NUMBER (n, 0);
1074: t = XINT (n);
1075: if (t <= 0)
1076: return Qnil;
1077:
1078: #ifdef subprocesses
1079: wait_reading_process_input (t, 0, 0);
1080: #else /* No subprocesses */
1081: immediate_quit = 1;
1082: QUIT;
1083:
1084: #if defined(HAVE_SELECT) && defined(HAVE_TIMEVAL)
1085: gettimeofday (&end_time, &garbage1);
1086: end_time.tv_sec += t;
1087:
1088: while (1)
1089: {
1090: gettimeofday (&timeout, &garbage1);
1091: timeout.tv_sec = end_time.tv_sec - timeout.tv_sec;
1092: timeout.tv_usec = end_time.tv_usec - timeout.tv_usec;
1093: if (timeout.tv_usec < 0)
1094: timeout.tv_usec += 1000000,
1095: timeout.tv_sec--;
1096: if (timeout.tv_sec < 0)
1097: break;
1098: if (!select (1, 0, 0, 0, &timeout))
1099: break;
1100: }
1101: #else /* not both HAVE_SELECT and HAVE_TIMEVAL */
1102: /* Is it safe to quit out of `sleep'? I'm afraid to trust it. */
1103: sleep (t);
1104: #endif /* not both HAVE_SELECT and HAVE_TIMEVAL */
1105:
1106: immediate_quit = 0;
1107: #endif /* no subprocesses */
1108: return Qnil;
1109: }
1110:
1111: DEFUN ("sit-for", Fsit_for, Ssit_for, 1, 1, 0,
1112: "Perform redisplay, then wait for ARG seconds or until input is available")
1113: (n)
1114: Lisp_Object n;
1115: {
1116: #ifndef subprocesses
1117: #ifdef HAVE_TIMEVAL
1118: struct timeval timeout;
1119: #else
1120: int timeout_sec;
1121: #endif
1122: int waitchannels;
1123: #endif /* no subprocesses */
1124:
1125: CHECK_NUMBER (n, 0);
1126:
1127: if (detect_input_pending ())
1128: return Qnil;
1129:
1130: DoDsp (1); /* Make the screen correct */
1131: if (XINT (n) <= 0) return Qnil;
1132:
1133: #ifdef subprocesses
1134: #ifdef SIGIO
1135: gobble_input ();
1136: #endif /* SIGIO */
1137: wait_reading_process_input (XINT (n), 1, 1);
1138: #else /* no subprocesses */
1139: immediate_quit = 1;
1140: QUIT;
1141:
1142: waitchannels = 1;
1143: #ifndef HAVE_TIMEVAL
1144: timeout_sec = XINT (n);
1145: select (1, &waitchannels, 0, 0, &timeout_sec);
1146: #else /* HAVE_TIMEVAL */
1147: timeout.tv_sec = XINT (n);
1148: timeout.tv_usec = 0;
1149: select (1, &waitchannels, 0, 0, &timeout);
1150: #endif /* HAVE_TIMEVAL */
1151:
1152: immediate_quit = 0;
1153: #endif /* no subprocesses */
1154: return Qnil;
1155: }
1156:
1157: char *terminal_type;
1158:
1159: /* Initialization done when Emacs fork is started, before doing stty. */
1160: /* Determine terminal type and set terminal_driver */
1161: /* Then invoke its decoding routine to set up variables
1162: in the terminal package */
1163:
1164: init_display ()
1165: {
1166: MetaFlag = 0;
1167: inverse_video = 0;
1168:
1169: /* Look at the TERM variable and set terminal_driver. */
1170:
1171: terminal_type = (char *) getenv ("TERM");
1172: if (!terminal_type)
1173: {
1174: fprintf (stderr, "Please set the environment variable TERM; see tset(1).\n");
1175: exit (1);
1176: }
1177: #ifdef HAVE_X_WINDOWS
1178: if (!strncmp (terminal_type, "xterm", 5))
1179: x_term_init ();
1180: else
1181: #endif /* HAVE_X_WINDOWS */
1182: term_init (terminal_type);
1183:
1184: make_display_lines ();
1185:
1186: cursX = 0; /* X and Y coordinates of the cursor */
1187: cursY = 0; /* between updates. */
1188: }
1189:
1190: syms_of_display ()
1191: {
1192: defsubr (&Sopen_termscript);
1193: defsubr (&Sding);
1194: defsubr (&Ssit_for);
1195: defsubr (&Sscreen_height);
1196: defsubr (&Sscreen_width);
1197: defsubr (&Sset_screen_height);
1198: defsubr (&Sset_screen_width);
1199: defsubr (&Ssleep_for);
1200: defsubr (&Sbaud_rate);
1201: defsubr (&Ssend_string_to_terminal);
1202:
1203: DefBoolVar ("inverse-video", &inverse_video,
1204: "*Non-nil means use inverse-video.");
1205: DefBoolVar ("visible-bell", &visible_bell,
1206: "*Non-nil means try to flash the screen to represent a bell.");
1207: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.