xref: /original-bsd/usr.bin/window/xxflush.c (revision da818fbb)
1 /*
2  * Copyright (c) 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)xxflush.c	3.4 (Berkeley) 09/15/89";
20 #endif /* not lint */
21 
22 #include "ww.h"
23 #include "xx.h"
24 #include "tt.h"
25 
26 xxflush(intr)
27 	register intr;
28 {
29 	register struct xx *xp, *xq;
30 
31 	for (xp = xx_head; xp != 0 && !(intr && wwinterrupt()); xp = xq) {
32 		switch (xp->cmd) {
33 		case xc_move:
34 			if (xp->link == 0)
35 				(*tt.tt_move)(xp->arg0, xp->arg1);
36 			break;
37 		case xc_scroll:
38 			xxflush_scroll(xp);
39 			break;
40 		case xc_inschar:
41 			(*tt.tt_move)(xp->arg0, xp->arg1);
42 			tt.tt_nmodes = xp->arg3;
43 			(*tt.tt_inschar)(xp->arg2);
44 			break;
45 		case xc_insspace:
46 			(*tt.tt_move)(xp->arg0, xp->arg1);
47 			(*tt.tt_insspace)(xp->arg2);
48 			break;
49 		case xc_delchar:
50 			(*tt.tt_move)(xp->arg0, xp->arg1);
51 			(*tt.tt_delchar)(xp->arg2);
52 			break;
53 		case xc_clear:
54 			(*tt.tt_clear)();
55 			break;
56 		case xc_clreos:
57 			(*tt.tt_move)(xp->arg0, xp->arg1);
58 			(*tt.tt_clreos)();
59 			break;
60 		case xc_clreol:
61 			(*tt.tt_move)(xp->arg0, xp->arg1);
62 			(*tt.tt_clreol)();
63 			break;
64 		case xc_write:
65 			(*tt.tt_move)(xp->arg0, xp->arg1);
66 			tt.tt_nmodes = xp->arg3;
67 			(*tt.tt_write)(xp->buf, xp->arg2);
68 			break;
69 		}
70 		xq = xp->link;
71 		xxfree(xp);
72 	}
73 	if ((xx_head = xp) == 0) {
74 		xx_tail = 0;
75 		xxbufp = xxbuf;
76 	}
77 	(*tt.tt_flush)();
78 }
79 
80 xxflush_scroll(xp)
81 	register struct xx *xp;
82 {
83 	register struct xx *xq;
84 
85  top:
86 	if (xp->arg0 == 0)
87 		return;
88 	/*
89 	 * We handle retain (da and db) by putting the burden on scrolling up,
90 	 * which is the less common operation.  It must ensure that
91 	 * text is not pushed below the screen, so scrolling down doesn't
92 	 * have to worry about it.
93 	 *
94 	 * Try scrolling region (or scrolling the whole screen) first.
95 	 * Can we assume "sr" doesn't push text below the screen
96 	 * so we don't have to worry about retain below?
97 	 * What about scrolling down with a newline?  It probably does
98 	 * push text above (with da).  Scrolling up would then have
99 	 * to take care of that.
100 	 * It's easy to be fool proof, but that slows things down.
101 	 * The current solution is to disallow tt_scroll_up if da or db is true
102 	 * but cs (scrolling region) is not.  Again, we sacrifice scrolling
103 	 * up in favor of scrolling down.  The idea is having scrolling regions
104 	 * probably means we can scroll (even the whole screen) with impunity.
105 	 * This lets us work efficiently on simple terminals (use newline
106 	 * on the bottom to scroll), on any terminal without retain, and
107 	 * on vt100 style scrolling regions (I think).
108 	 */
109 	if (xp->arg0 > 0) {
110 		if ((xq = xp->link) != 0 && xq->cmd == xc_scroll &&
111 		    xp->arg2 == xq->arg2 && xq->arg0 < 0) {
112 			if (xp->arg1 < xq->arg1) {
113 				if (xp->arg2 - xp->arg0 <= xq->arg1) {
114 					xq->arg0 = xp->arg0;
115 					xq->arg1 = xp->arg1;
116 					xq->arg2 = xp->arg2;
117 					return;
118 				}
119 				xp->arg2 = xq->arg1 + xp->arg0;
120 				xq->arg0 += xp->arg0;
121 				xq->arg1 = xp->arg2;
122 				if (xq->arg0 > 0)
123 					xq->arg1 -= xq->arg0;
124 				goto top;
125 			} else {
126 				if (xp->arg1 - xq->arg0 >= xp->arg2)
127 					return;
128 				xq->arg2 = xp->arg1 - xq->arg0;
129 				xp->arg0 += xq->arg0;
130 				xp->arg1 = xq->arg2;
131 				if (xp->arg0 < 0)
132 					xp->arg1 += xp->arg0;
133 				goto top;
134 			}
135 		}
136 		if (xp->arg0 > xp->arg2 - xp->arg1)
137 			xp->arg0 = xp->arg2 - xp->arg1;
138 		if (tt.tt_scroll_down) {
139 			if (tt.tt_scroll_top != xp->arg1 ||
140 			    tt.tt_scroll_bot != xp->arg2 - 1) {
141 				if (tt.tt_setscroll == 0)
142 					goto down;
143 				(*tt.tt_setscroll)(xp->arg1, xp->arg2 - 1);
144 			}
145 			tt.tt_scroll_down(xp->arg0);
146 		} else {
147 		down:
148 			(*tt.tt_move)(xp->arg1, 0);
149 			(*tt.tt_delline)(xp->arg0);
150 			if (xp->arg2 < tt.tt_nrow) {
151 				(*tt.tt_move)(xp->arg2 - xp->arg0, 0);
152 				(*tt.tt_insline)(xp->arg0);
153 			}
154 		}
155 	} else {
156 		xp->arg0 = - xp->arg0;
157 		if (xp->arg0 > xp->arg2 - xp->arg1)
158 			xp->arg0 = xp->arg2 - xp->arg1;
159 		if (tt.tt_scroll_up) {
160 			if (tt.tt_scroll_top != xp->arg1 ||
161 			    tt.tt_scroll_bot != xp->arg2 - 1) {
162 				if (tt.tt_setscroll == 0)
163 					goto up;
164 				(*tt.tt_setscroll)(xp->arg1, xp->arg2 - 1);
165 			}
166 			tt.tt_scroll_up(xp->arg0);
167 		} else  {
168 		up:
169 			if (tt.tt_retain || xp->arg2 != tt.tt_nrow) {
170 				(*tt.tt_move)(xp->arg2 - xp->arg0, 0);
171 				(*tt.tt_delline)(xp->arg0);
172 			}
173 			(*tt.tt_move)(xp->arg1, 0);
174 			(*tt.tt_insline)(xp->arg0);
175 		}
176 	}
177 }
178