ncurses 5.3
[ncurses.git] / ncurses / base / resizeterm.c
1 /****************************************************************************
2  * Copyright (c) 1998-2001,2002 Free Software Foundation, Inc.              *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28
29 /****************************************************************************
30  *  Author: Thomas E. Dickey                                                *
31  ****************************************************************************/
32
33 /*
34  * This is an extension to the curses library.  It provides callers with a hook
35  * into the NCURSES data to resize windows, primarily for use by programs
36  * running in an X Window terminal (e.g., xterm).  I abstracted this module
37  * from my application library for NCURSES because it must be compiled with
38  * the private data structures -- T.Dickey 1995/7/4.
39  */
40
41 #include <curses.priv.h>
42 #include <term.h>
43
44 MODULE_ID("$Id: resizeterm.c,v 1.14 2002/07/13 21:32:57 tom Exp $")
45
46 #define stolen_lines (screen_lines - SP->_lines_avail)
47
48 NCURSES_EXPORT(bool)
49 is_term_resized(int ToLines, int ToCols)
50 {
51     return (ToLines != screen_lines
52             || ToCols != screen_columns);
53 }
54
55 /*
56  * Return the number of levels of child-windows under the current window.
57  */
58 static int
59 child_depth(WINDOW *cmp)
60 {
61     int depth = 0;
62
63     if (cmp != 0) {
64         WINDOWLIST *wp;
65
66         for (wp = _nc_windows; wp != 0; wp = wp->next) {
67             WINDOW *tst = &(wp->win);
68             if (tst->_parent == cmp) {
69                 depth = 1 + child_depth(tst);
70                 break;
71             }
72         }
73     }
74     return depth;
75 }
76
77 /*
78  * Return the number of levels of parent-windows above the current window.
79  */
80 static int
81 parent_depth(WINDOW *cmp)
82 {
83     int depth = 0;
84
85     if (cmp != 0) {
86         WINDOW *tst;
87         while ((tst = cmp->_parent) != 0) {
88             ++depth;
89             cmp = tst;
90         }
91     }
92     return depth;
93 }
94
95 /*
96  * FIXME: must adjust position so it's within the parent!
97  */
98 static int
99 adjust_window(WINDOW *win, int ToLines, int ToCols, int stolen)
100 {
101     int result;
102     int bottom = screen_lines + SP->_topstolen - stolen;
103     int myLines = win->_maxy + 1;
104     int myCols = win->_maxx + 1;
105
106     T((T_CALLED("adjust_window(%p,%d,%d) currently %dx%d at %d,%d"),
107        win, ToLines, ToCols,
108        getmaxy(win), getmaxx(win),
109        getbegy(win), getbegx(win)));
110
111     if (win->_begy >= bottom) {
112         win->_begy += (ToLines - screen_lines);
113     } else {
114         if (myLines == screen_lines - stolen
115             && ToLines != screen_lines)
116             myLines = ToLines - stolen;
117         else if (myLines == screen_lines
118                  && ToLines != screen_lines)
119             myLines = ToLines;
120     }
121
122     if (myLines > ToLines)
123         myLines = ToLines;
124
125     if (myCols > ToCols)
126         myCols = ToCols;
127
128     if (myLines == screen_lines
129         && ToLines != screen_lines)
130         myCols = ToLines;
131
132     if (myCols == screen_columns
133         && ToCols != screen_columns)
134         myCols = ToCols;
135
136     result = wresize(win, myLines, myCols);
137     returnCode(result);
138 }
139
140 /*
141  * If we're decreasing size, recursively search for windows that have no
142  * children, decrease those to fit, then decrease the containing window, etc.
143  */
144 static int
145 decrease_size(int ToLines, int ToCols, int stolen)
146 {
147     bool found;
148     int depth = 0;
149     WINDOWLIST *wp;
150
151     T((T_CALLED("decrease_size(%d, %d)"), ToLines, ToCols));
152
153     do {
154         found = FALSE;
155         TR(TRACE_UPDATE, ("decreasing size of windows to %dx%d, depth=%d",
156                           ToLines, ToCols, depth));
157         for (wp = _nc_windows; wp != 0; wp = wp->next) {
158             WINDOW *win = &(wp->win);
159
160             if (!(win->_flags & _ISPAD)) {
161                 if (child_depth(win) == depth) {
162                     if (adjust_window(win, ToLines, ToCols, stolen) != OK)
163                         returnCode(ERR);
164                 }
165             }
166         }
167         ++depth;
168     } while (found);
169     returnCode(OK);
170 }
171
172 /*
173  * If we're increasing size, recursively search for windows that have no
174  * parent, increase those to fit, then increase the contained window, etc.
175  */
176 static int
177 increase_size(int ToLines, int ToCols, int stolen)
178 {
179     bool found;
180     int depth = 0;
181     WINDOWLIST *wp;
182
183     T((T_CALLED("increase_size(%d, %d)"), ToLines, ToCols));
184
185     do {
186         found = FALSE;
187         TR(TRACE_UPDATE, ("increasing size of windows to %dx%d, depth=%d",
188                           ToLines, ToCols, depth));
189         for (wp = _nc_windows; wp != 0; wp = wp->next) {
190             WINDOW *win = &(wp->win);
191
192             if (!(win->_flags & _ISPAD)) {
193                 if (parent_depth(win) == depth) {
194                     if (adjust_window(win, ToLines, ToCols, stolen) != OK)
195                         returnCode(ERR);
196                 }
197             }
198         }
199         ++depth;
200     } while (found);
201     returnCode(OK);
202 }
203
204 /*
205  * This function reallocates NCURSES window structures, with no side-effects
206  * such as ungetch().
207  */
208 NCURSES_EXPORT(int)
209 resize_term(int ToLines, int ToCols)
210 {
211     int result = OK;
212     int was_stolen = (screen_lines - SP->_lines_avail);
213
214     T((T_CALLED("resize_term(%d,%d) old(%d,%d)"),
215        ToLines, ToCols,
216        screen_lines, screen_columns));
217
218     if (is_term_resized(ToLines, ToCols)) {
219         int myLines = screen_lines;
220         int myCols = screen_columns;
221
222         if (ToLines > screen_lines) {
223             increase_size(myLines = ToLines, myCols, was_stolen);
224         }
225
226         if (ToCols > screen_columns) {
227             increase_size(myLines, myCols = ToCols, was_stolen);
228         }
229
230         if (ToLines < myLines ||
231             ToCols < myCols) {
232             decrease_size(ToLines, ToCols, was_stolen);
233         }
234
235         screen_lines = lines = ToLines;
236         screen_columns = columns = ToCols;
237
238         SP->_lines_avail = lines - was_stolen;
239
240         if (SP->oldhash) {
241             FreeAndNull(SP->oldhash);
242         }
243         if (SP->newhash) {
244             FreeAndNull(SP->newhash);
245         }
246     }
247
248     /*
249      * Always update LINES, to allow for call from lib_doupdate.c which
250      * needs to have the count adjusted by the stolen (ripped off) lines.
251      */
252     LINES = ToLines - was_stolen;
253     COLS = ToCols;
254
255     returnCode(result);
256 }
257
258 /*
259  * This function reallocates NCURSES window structures.  It is invoked in
260  * response to a SIGWINCH interrupt.  Other user-defined windows may also need
261  * to be reallocated.
262  *
263  * Because this performs memory allocation, it should not (in general) be
264  * invoked directly from the signal handler.
265  */
266 NCURSES_EXPORT(int)
267 resizeterm(int ToLines, int ToCols)
268 {
269     int result = OK;
270
271     SP->_sig_winch = FALSE;
272
273     T((T_CALLED("resizeterm(%d,%d) old(%d,%d)"),
274        ToLines, ToCols,
275        screen_lines, screen_columns));
276
277     if (is_term_resized(ToLines, ToCols)) {
278
279 #if USE_SIGWINCH
280         ungetch(KEY_RESIZE);    /* so application can know this */
281         clearok(curscr, TRUE);  /* screen contents are unknown */
282 #endif
283
284         result = resize_term(ToLines, ToCols);
285     }
286
287     returnCode(result);
288 }