xref: /openbsd-src/lib/libcurses/base/lib_pad.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /* $OpenBSD: lib_pad.c,v 1.5 2010/01/12 23:22:06 nicm Exp $ */
2 
3 /****************************************************************************
4  * Copyright (c) 1998-2004,2006 Free Software Foundation, Inc.                   *
5  *                                                                          *
6  * Permission is hereby granted, free of charge, to any person obtaining a  *
7  * copy of this software and associated documentation files (the            *
8  * "Software"), to deal in the Software without restriction, including      *
9  * without limitation the rights to use, copy, modify, merge, publish,      *
10  * distribute, distribute with modifications, sublicense, and/or sell       *
11  * copies of the Software, and to permit persons to whom the Software is    *
12  * furnished to do so, subject to the following conditions:                 *
13  *                                                                          *
14  * The above copyright notice and this permission notice shall be included  *
15  * in all copies or substantial portions of the Software.                   *
16  *                                                                          *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
20  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
23  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
24  *                                                                          *
25  * Except as contained in this notice, the name(s) of the above copyright   *
26  * holders shall not be used in advertising or otherwise to promote the     *
27  * sale, use or other dealings in this Software without prior written       *
28  * authorization.                                                           *
29  ****************************************************************************/
30 
31 /****************************************************************************
32  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
33  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
34  ****************************************************************************/
35 
36 /*
37  * lib_pad.c
38  * newpad	-- create a new pad
39  * pnoutrefresh -- refresh a pad, no update
40  * pechochar	-- add a char to a pad and refresh
41  */
42 
43 #include <curses.priv.h>
44 
45 MODULE_ID("$Id: lib_pad.c,v 1.5 2010/01/12 23:22:06 nicm Exp $")
46 
47 NCURSES_EXPORT(WINDOW *)
48 newpad(int l, int c)
49 {
50     WINDOW *win;
51     NCURSES_CH_T *ptr;
52     int i;
53 
54     T((T_CALLED("newpad(%d, %d)"), l, c));
55 
56     if (l <= 0 || c <= 0)
57 	returnWin(0);
58 
59     if ((win = _nc_makenew(l, c, 0, 0, _ISPAD)) == NULL)
60 	returnWin(0);
61 
62     for (i = 0; i < l; i++) {
63 	if_USE_SCROLL_HINTS(win->_line[i].oldindex = _NEWINDEX);
64 	if ((win->_line[i].text = typeCalloc(NCURSES_CH_T, ((size_t) c))) == 0) {
65 	    (void) _nc_freewin(win);
66 	    returnWin(0);
67 	}
68 	for (ptr = win->_line[i].text; ptr < win->_line[i].text + c; ptr++)
69 	    SetChar(*ptr, BLANK_TEXT, BLANK_ATTR);
70     }
71 
72     returnWin(win);
73 }
74 
75 NCURSES_EXPORT(WINDOW *)
76 subpad(WINDOW *orig, int l, int c, int begy, int begx)
77 {
78     WINDOW *win = (WINDOW *) 0;
79 
80     T((T_CALLED("subpad(%d, %d)"), l, c));
81 
82     if (orig) {
83 	if (!(orig->_flags & _ISPAD)
84 	    || ((win = derwin(orig, l, c, begy, begx)) == NULL))
85 	    returnWin(0);
86     }
87     returnWin(win);
88 }
89 
90 NCURSES_EXPORT(int)
91 prefresh(WINDOW *win,
92 	 int pminrow,
93 	 int pmincol,
94 	 int sminrow,
95 	 int smincol,
96 	 int smaxrow,
97 	 int smaxcol)
98 {
99     T((T_CALLED("prefresh()")));
100     if (pnoutrefresh(win, pminrow, pmincol, sminrow, smincol, smaxrow,
101 		     smaxcol) != ERR
102 	&& doupdate() != ERR) {
103 	returnCode(OK);
104     }
105     returnCode(ERR);
106 }
107 
108 NCURSES_EXPORT(int)
109 pnoutrefresh(WINDOW *win,
110 	     int pminrow,
111 	     int pmincol,
112 	     int sminrow,
113 	     int smincol,
114 	     int smaxrow,
115 	     int smaxcol)
116 {
117     NCURSES_SIZE_T i, j;
118     NCURSES_SIZE_T m, n;
119     NCURSES_SIZE_T pmaxrow;
120     NCURSES_SIZE_T pmaxcol;
121 
122 #if USE_SCROLL_HINTS
123     const int my_len = 2;	/* parameterize the threshold for hardscroll */
124     NCURSES_SIZE_T displaced;
125     bool wide;
126 #endif
127 
128     T((T_CALLED("pnoutrefresh(%p, %d, %d, %d, %d, %d, %d)"),
129        win, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol));
130 
131     if (win == 0)
132 	returnCode(ERR);
133 
134     if (!(win->_flags & _ISPAD))
135 	returnCode(ERR);
136 
137     /* negative values are interpreted as zero */
138     if (pminrow < 0)
139 	pminrow = 0;
140     if (pmincol < 0)
141 	pmincol = 0;
142     if (sminrow < 0)
143 	sminrow = 0;
144     if (smincol < 0)
145 	smincol = 0;
146 
147     pmaxrow = pminrow + smaxrow - sminrow;
148     pmaxcol = pmincol + smaxcol - smincol;
149 
150     T((" pminrow + smaxrow - sminrow %ld, win->_maxy %ld",
151        (long) pmaxrow, (long) win->_maxy));
152     T((" pmincol + smaxcol - smincol %ld, win->_maxx %ld",
153        (long) pmaxcol, (long) win->_maxx));
154 
155     /*
156      * Trim the caller's screen size back to the actual limits.
157      */
158     if (pmaxrow > win->_maxy) {
159 	smaxrow -= (pmaxrow - win->_maxy);
160 	pmaxrow = pminrow + smaxrow - sminrow;
161     }
162     if (pmaxcol > win->_maxx) {
163 	smaxcol -= (pmaxcol - win->_maxx);
164 	pmaxcol = pmincol + smaxcol - smincol;
165     }
166 
167     if (smaxrow >= screen_lines
168 	|| smaxcol >= screen_columns
169 	|| sminrow > smaxrow
170 	|| smincol > smaxcol)
171 	returnCode(ERR);
172 
173     T(("pad being refreshed"));
174 
175 #if USE_SCROLL_HINTS
176     if (win->_pad._pad_y >= 0) {
177 	displaced = pminrow - win->_pad._pad_y
178 	    - (sminrow - win->_pad._pad_top);
179 	T(("pad being shifted by %d line(s)", displaced));
180     } else
181 	displaced = 0;
182 #endif
183 
184     /*
185      * For pure efficiency, we'd want to transfer scrolling information
186      * from the pad to newscr whenever the window is wide enough that
187      * its update will dominate the cost of the update for the horizontal
188      * band of newscr that it occupies.  Unfortunately, this threshold
189      * tends to be complex to estimate, and in any case scrolling the
190      * whole band and rewriting the parts outside win's image would look
191      * really ugly.  So.  What we do is consider the pad "wide" if it
192      * either (a) occupies the whole width of newscr, or (b) occupies
193      * all but at most one column on either vertical edge of the screen
194      * (this caters to fussy people who put boxes around full-screen
195      * windows).  Note that changing this formula will not break any code,
196      * merely change the costs of various update cases.
197      */
198 #if USE_SCROLL_HINTS
199     wide = (smincol < my_len && smaxcol > (newscr->_maxx - my_len));
200 #endif
201 
202     for (i = pminrow, m = sminrow + win->_yoffset;
203 	 i <= pmaxrow && m <= newscr->_maxy;
204 	 i++, m++) {
205 	register struct ldat *nline = &newscr->_line[m];
206 	register struct ldat *oline = &win->_line[i];
207 	for (j = pmincol, n = smincol; j <= pmaxcol; j++, n++) {
208 	    NCURSES_CH_T ch = oline->text[j];
209 #if USE_WIDEC_SUPPORT
210 	    /*
211 	     * Special case for leftmost character of the displayed area.
212 	     * Only half of a double-width character may be visible.
213 	     */
214 	    if (j == pmincol
215 		&& j > 0
216 		&& isWidecExt(ch)) {
217 		SetChar(ch, L(' '), AttrOf(oline->text[j - 1]));
218 	    }
219 #endif
220 	    if (!CharEq(ch, nline->text[n])) {
221 		nline->text[n] = ch;
222 		CHANGED_CELL(nline, n);
223 	    }
224 	}
225 
226 #if USE_SCROLL_HINTS
227 	if (wide) {
228 	    int nind = m + displaced;
229 	    if (oline->oldindex < 0
230 		|| nind < sminrow
231 		|| nind > smaxrow) {
232 		nind = _NEWINDEX;
233 	    } else if (displaced) {
234 		register struct ldat *pline = &curscr->_line[nind];
235 		for (j = 0; j <= my_len; j++) {
236 		    int k = newscr->_maxx - j;
237 		    if (pline->text[j] != nline->text[j]
238 			|| pline->text[k] != nline->text[k]) {
239 			nind = _NEWINDEX;
240 			break;
241 		    }
242 		}
243 	    }
244 
245 	    nline->oldindex = nind;
246 	}
247 #endif /* USE_SCROLL_HINTS */
248 	oline->firstchar = oline->lastchar = _NOCHANGE;
249 	if_USE_SCROLL_HINTS(oline->oldindex = i);
250     }
251 
252     /*
253      * Clean up debris from scrolling or resizing the pad, so we do not
254      * accidentally pick up the index value during the next call to this
255      * procedure.  The only rows that should have an index value are those
256      * that are displayed during this cycle.
257      */
258 #if USE_SCROLL_HINTS
259     for (i = pminrow - 1; (i >= 0) && (win->_line[i].oldindex >= 0); i--)
260 	win->_line[i].oldindex = _NEWINDEX;
261     for (i = pmaxrow + 1; (i <= win->_maxy)
262 	 && (win->_line[i].oldindex >= 0); i++)
263 	win->_line[i].oldindex = _NEWINDEX;
264 #endif
265 
266     win->_begx = smincol;
267     win->_begy = sminrow;
268 
269     if (win->_clear) {
270 	win->_clear = FALSE;
271 	newscr->_clear = TRUE;
272     }
273 
274     /*
275      * Use the pad's current position, if it will be visible.
276      * If not, don't do anything; it's not an error.
277      */
278     if (win->_leaveok == FALSE
279 	&& win->_cury >= pminrow
280 	&& win->_curx >= pmincol
281 	&& win->_cury <= pmaxrow
282 	&& win->_curx <= pmaxcol) {
283 	newscr->_cury = win->_cury - pminrow + win->_begy + win->_yoffset;
284 	newscr->_curx = win->_curx - pmincol + win->_begx;
285     }
286     newscr->_leaveok = win->_leaveok;
287     win->_flags &= ~_HASMOVED;
288 
289     /*
290      * Update our cache of the line-numbers that we displayed from the pad.
291      * We will use this on subsequent calls to this function to derive
292      * values to stuff into 'oldindex[]' -- for scrolling optimization.
293      */
294     win->_pad._pad_y = pminrow;
295     win->_pad._pad_x = pmincol;
296     win->_pad._pad_top = sminrow;
297     win->_pad._pad_left = smincol;
298     win->_pad._pad_bottom = smaxrow;
299     win->_pad._pad_right = smaxcol;
300 
301     returnCode(OK);
302 }
303 
304 NCURSES_EXPORT(int)
305 pechochar(WINDOW *pad, const chtype ch)
306 {
307     T((T_CALLED("pechochar(%p, %s)"), pad, _tracechtype(ch)));
308 
309     if (pad == 0)
310 	returnCode(ERR);
311 
312     if (!(pad->_flags & _ISPAD))
313 	returnCode(wechochar(pad, ch));
314 
315     waddch(pad, ch);
316     prefresh(pad, pad->_pad._pad_y,
317 	     pad->_pad._pad_x,
318 	     pad->_pad._pad_top,
319 	     pad->_pad._pad_left,
320 	     pad->_pad._pad_bottom,
321 	     pad->_pad._pad_right);
322 
323     returnCode(OK);
324 }
325