1/**************************************************************************** 2 * Copyright (c) 1998-2002,2004 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 44MODULE_ID("$Id: resizeterm.c,v 1.17 2004/07/31 20:24:38 tom Exp $") 45 46#define stolen_lines (screen_lines - SP->_lines_avail) 47 48static int current_lines; 49static int current_cols; 50 51#ifdef TRACE 52static void 53show_window_sizes(const char *name) 54{ 55 WINDOWLIST *wp; 56 57 _tracef("%s resizing: %2d x %2d (%2d x %2d)", name, LINES, COLS, 58 screen_lines, screen_columns); 59 for (wp = _nc_windows; wp != 0; wp = wp->next) { 60 _tracef(" window %p is %2d x %2d at %2d,%2d", 61 &(wp->win), 62 wp->win._maxy + 1, 63 wp->win._maxx + 1, 64 wp->win._begy, 65 wp->win._begx); 66 } 67} 68#endif 69 70NCURSES_EXPORT(bool) 71is_term_resized(int ToLines, int ToCols) 72{ 73 T((T_CALLED("is_term_resized(%d, %d)"), ToLines, ToCols)); 74 returnCode(ToLines > 0 75 && ToCols > 0 76 && (ToLines != screen_lines 77 || ToCols != screen_columns)); 78} 79 80/* 81 * Return the number of levels of child-windows under the current window. 82 */ 83static int 84child_depth(WINDOW *cmp) 85{ 86 int depth = 0; 87 88 if (cmp != 0) { 89 WINDOWLIST *wp; 90 91 for (wp = _nc_windows; wp != 0; wp = wp->next) { 92 WINDOW *tst = &(wp->win); 93 if (tst->_parent == cmp) { 94 depth = 1 + child_depth(tst); 95 break; 96 } 97 } 98 } 99 return depth; 100} 101 102/* 103 * Return the number of levels of parent-windows above the current window. 104 */ 105static int 106parent_depth(WINDOW *cmp) 107{ 108 int depth = 0; 109 110 if (cmp != 0) { 111 WINDOW *tst; 112 while ((tst = cmp->_parent) != 0) { 113 ++depth; 114 cmp = tst; 115 } 116 } 117 return depth; 118} 119 120/* 121 * FIXME: must adjust position so it's within the parent! 122 */ 123static int 124adjust_window(WINDOW *win, int ToLines, int ToCols, int stolen) 125{ 126 int result; 127 int bottom = current_lines + SP->_topstolen - stolen; 128 int myLines = win->_maxy + 1; 129 int myCols = win->_maxx + 1; 130 131 T((T_CALLED("adjust_window(%p,%d,%d) currently %dx%d at %d,%d"), 132 win, ToLines, ToCols, 133 getmaxy(win), getmaxx(win), 134 getbegy(win), getbegx(win))); 135 136 if (win->_begy >= bottom) { 137 win->_begy += (ToLines - current_lines); 138 } else { 139 if (myLines == current_lines - stolen 140 && ToLines != current_lines) 141 myLines = ToLines - stolen; 142 else if (myLines == current_lines 143 && ToLines != current_lines) 144 myLines = ToLines; 145 } 146 147 if (myLines > ToLines) 148 myLines = ToLines; 149 150 if (myCols > ToCols) 151 myCols = ToCols; 152 153 if (myLines == current_lines 154 && ToLines != current_lines) 155 myLines = ToLines; 156 157 if (myCols == current_cols 158 && ToCols != current_cols) 159 myCols = ToCols; 160 161 result = wresize(win, myLines, myCols); 162 returnCode(result); 163} 164 165/* 166 * If we're decreasing size, recursively search for windows that have no 167 * children, decrease those to fit, then decrease the containing window, etc. 168 */ 169static int 170decrease_size(int ToLines, int ToCols, int stolen) 171{ 172 bool found; 173 int depth = 0; 174 WINDOWLIST *wp; 175 176 T((T_CALLED("decrease_size(%d, %d)"), ToLines, ToCols)); 177 178 do { 179 found = FALSE; 180 TR(TRACE_UPDATE, ("decreasing size of windows to %dx%d, depth=%d", 181 ToLines, ToCols, depth)); 182 for (wp = _nc_windows; wp != 0; wp = wp->next) { 183 WINDOW *win = &(wp->win); 184 185 if (!(win->_flags & _ISPAD)) { 186 if (child_depth(win) == depth) { 187 found = TRUE; 188 if (adjust_window(win, ToLines, ToCols, stolen) != OK) 189 returnCode(ERR); 190 } 191 } 192 } 193 ++depth; 194 } while (found); 195 returnCode(OK); 196} 197 198/* 199 * If we're increasing size, recursively search for windows that have no 200 * parent, increase those to fit, then increase the contained window, etc. 201 */ 202static int 203increase_size(int ToLines, int ToCols, int stolen) 204{ 205 bool found; 206 int depth = 0; 207 WINDOWLIST *wp; 208 209 T((T_CALLED("increase_size(%d, %d)"), ToLines, ToCols)); 210 211 do { 212 found = FALSE; 213 TR(TRACE_UPDATE, ("increasing size of windows to %dx%d, depth=%d", 214 ToLines, ToCols, depth)); 215 for (wp = _nc_windows; wp != 0; wp = wp->next) { 216 WINDOW *win = &(wp->win); 217 218 if (!(win->_flags & _ISPAD)) { 219 if (parent_depth(win) == depth) { 220 found = TRUE; 221 if (adjust_window(win, ToLines, ToCols, stolen) != OK) 222 returnCode(ERR); 223 } 224 } 225 } 226 ++depth; 227 } while (found); 228 returnCode(OK); 229} 230 231/* 232 * This function reallocates NCURSES window structures, with no side-effects 233 * such as ungetch(). 234 */ 235NCURSES_EXPORT(int) 236resize_term(int ToLines, int ToCols) 237{ 238 int result = OK; 239 int was_stolen = (screen_lines - SP->_lines_avail); 240 241 T((T_CALLED("resize_term(%d,%d) old(%d,%d)"), 242 ToLines, ToCols, 243 screen_lines, screen_columns)); 244 245 if (is_term_resized(ToLines, ToCols)) { 246 int myLines = current_lines = screen_lines; 247 int myCols = current_cols = screen_columns; 248 249#ifdef TRACE 250 if (_nc_tracing & TRACE_UPDATE) 251 show_window_sizes("before"); 252#endif 253 if (ToLines > screen_lines) { 254 increase_size(myLines = ToLines, myCols, was_stolen); 255 current_lines = myLines; 256 current_cols = myCols; 257 } 258 259 if (ToCols > screen_columns) { 260 increase_size(myLines, myCols = ToCols, was_stolen); 261 current_lines = myLines; 262 current_cols = myCols; 263 } 264 265 if (ToLines < myLines || 266 ToCols < myCols) { 267 decrease_size(ToLines, ToCols, was_stolen); 268 } 269 270 screen_lines = lines = ToLines; 271 screen_columns = columns = ToCols; 272 273 SP->_lines_avail = lines - was_stolen; 274 275 if (SP->oldhash) { 276 FreeAndNull(SP->oldhash); 277 } 278 if (SP->newhash) { 279 FreeAndNull(SP->newhash); 280 } 281#ifdef TRACE 282 if (_nc_tracing & TRACE_UPDATE) { 283 LINES = ToLines - was_stolen; 284 COLS = ToCols; 285 show_window_sizes("after"); 286 } 287#endif 288 } 289 290 /* 291 * Always update LINES, to allow for call from lib_doupdate.c which 292 * needs to have the count adjusted by the stolen (ripped off) lines. 293 */ 294 LINES = ToLines - was_stolen; 295 COLS = ToCols; 296 297 returnCode(result); 298} 299 300/* 301 * This function reallocates NCURSES window structures. It is invoked in 302 * response to a SIGWINCH interrupt. Other user-defined windows may also need 303 * to be reallocated. 304 * 305 * Because this performs memory allocation, it should not (in general) be 306 * invoked directly from the signal handler. 307 */ 308NCURSES_EXPORT(int) 309resizeterm(int ToLines, int ToCols) 310{ 311 int result = OK; 312 313 SP->_sig_winch = FALSE; 314 315 T((T_CALLED("resizeterm(%d,%d) old(%d,%d)"), 316 ToLines, ToCols, 317 screen_lines, screen_columns)); 318 319 if (is_term_resized(ToLines, ToCols)) { 320 321#if USE_SIGWINCH 322 ungetch(KEY_RESIZE); /* so application can know this */ 323 clearok(curscr, TRUE); /* screen contents are unknown */ 324#endif 325 326 result = resize_term(ToLines, ToCols); 327 } 328 329 returnCode(result); 330} 331