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