resizeterm.c revision 178867
1/**************************************************************************** 2 * Copyright (c) 1998-2007,2008 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.32 2008/05/03 14:28:55 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 (each_window(wp)) { 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 84/* 85 * Return true if the given dimensions do not match the internal terminal 86 * structure's size. 87 */ 88NCURSES_EXPORT(bool) 89is_term_resized(int ToLines, int ToCols) 90{ 91 T((T_CALLED("is_term_resized(%d, %d)"), ToLines, ToCols)); 92 returnCode(ToLines > 0 93 && ToCols > 0 94 && (ToLines != screen_lines 95 || ToCols != screen_columns)); 96} 97 98/* 99 */ 100static ripoff_t * 101ripped_window(WINDOW *win) 102{ 103 ripoff_t *result = 0; 104 ripoff_t *rop; 105 106 if (win != 0) { 107 for (each_ripoff(rop)) { 108 if (rop->win == win && rop->line != 0) { 109 result = rop; 110 break; 111 } 112 } 113 } 114 return result; 115} 116 117/* 118 * Returns the number of lines from the bottom for the beginning of a ripped 119 * off window. 120 */ 121static int 122ripped_bottom(WINDOW *win) 123{ 124 int result = 0; 125 ripoff_t *rop; 126 127 if (win != 0) { 128 for (each_ripoff(rop)) { 129 if (rop->line < 0) { 130 result -= rop->line; 131 if (rop->win == win) { 132 break; 133 } 134 } 135 } 136 } 137 return result; 138} 139 140/* 141 * Return the number of levels of child-windows under the current window. 142 */ 143static int 144child_depth(WINDOW *cmp) 145{ 146 int depth = 0; 147 148 if (cmp != 0) { 149 WINDOWLIST *wp; 150 151 for (each_window(wp)) { 152 WINDOW *tst = &(wp->win); 153 if (tst->_parent == cmp) { 154 depth = 1 + child_depth(tst); 155 break; 156 } 157 } 158 } 159 return depth; 160} 161 162/* 163 * Return the number of levels of parent-windows above the current window. 164 */ 165static int 166parent_depth(WINDOW *cmp) 167{ 168 int depth = 0; 169 170 if (cmp != 0) { 171 WINDOW *tst; 172 while ((tst = cmp->_parent) != 0) { 173 ++depth; 174 cmp = tst; 175 } 176 } 177 return depth; 178} 179 180/* 181 * FIXME: must adjust position so it's within the parent! 182 */ 183static int 184adjust_window(WINDOW *win, int ToLines, int ToCols, int stolen EXTRA_DCLS) 185{ 186 int result; 187 int bottom = CurLines + SP->_topstolen - stolen; 188 int myLines = win->_maxy + 1; 189 int myCols = win->_maxx + 1; 190 ripoff_t *rop = ripped_window(win); 191 192 T((T_CALLED("adjust_window(%p,%d,%d)%s depth %d/%d currently %ldx%ld at %ld,%ld"), 193 win, ToLines, ToCols, 194 (rop != 0) ? " (rip)" : "", 195 parent_depth(win), 196 child_depth(win), 197 (long) getmaxy(win), (long) getmaxx(win), 198 (long) getbegy(win) + win->_yoffset, (long) getbegx(win))); 199 200 if (rop != 0 && rop->line < 0) { 201 /* 202 * If it is a ripped-off window at the bottom of the screen, simply 203 * move it to the same relative position. 204 */ 205 win->_begy = ToLines - ripped_bottom(win) - 0 - win->_yoffset; 206 } else if (win->_begy >= bottom) { 207 /* 208 * If it is below the bottom of the new screen, move up by the same 209 * amount that the screen shrank. 210 */ 211 win->_begy += (ToLines - CurLines); 212 } else { 213 if (myLines == (CurLines - stolen) 214 && ToLines != CurLines) { 215 myLines = ToLines - stolen; 216 } else if (myLines == CurLines 217 && ToLines != CurLines) { 218 myLines = ToLines; 219 } 220 } 221 222 if (myLines > ToLines) { 223 myLines = ToLines; 224 } 225 226 if (myCols > ToCols) 227 myCols = ToCols; 228 229 if (myCols == CurCols 230 && ToCols != CurCols) 231 myCols = ToCols; 232 233 result = wresize(win, myLines, myCols); 234 returnCode(result); 235} 236 237/* 238 * If we're decreasing size, recursively search for windows that have no 239 * children, decrease those to fit, then decrease the containing window, etc. 240 */ 241static int 242decrease_size(int ToLines, int ToCols, int stolen EXTRA_DCLS) 243{ 244 bool found; 245 int depth = 0; 246 WINDOWLIST *wp; 247 248 T((T_CALLED("decrease_size(%d, %d)"), ToLines, ToCols)); 249 250 do { 251 found = FALSE; 252 TR(TRACE_UPDATE, ("decreasing size of windows to %dx%d, depth=%d", 253 ToLines, ToCols, depth)); 254 for (each_window(wp)) { 255 WINDOW *win = &(wp->win); 256 257 if (!(win->_flags & _ISPAD)) { 258 if (child_depth(win) == depth) { 259 found = TRUE; 260 if (adjust_window(win, ToLines, ToCols, 261 stolen EXTRA_ARGS) != OK) 262 returnCode(ERR); 263 } 264 } 265 } 266 ++depth; 267 } while (found); 268 returnCode(OK); 269} 270 271/* 272 * If we're increasing size, recursively search for windows that have no 273 * parent, increase those to fit, then increase the contained window, etc. 274 */ 275static int 276increase_size(int ToLines, int ToCols, int stolen EXTRA_DCLS) 277{ 278 bool found; 279 int depth = 0; 280 WINDOWLIST *wp; 281 282 T((T_CALLED("increase_size(%d, %d)"), ToLines, ToCols)); 283 284 do { 285 found = FALSE; 286 TR(TRACE_UPDATE, ("increasing size of windows to %dx%d, depth=%d", 287 ToLines, ToCols, depth)); 288 for (each_window(wp)) { 289 WINDOW *win = &(wp->win); 290 291 if (!(win->_flags & _ISPAD)) { 292 if (parent_depth(win) == depth) { 293 found = TRUE; 294 if (adjust_window(win, ToLines, ToCols, 295 stolen EXTRA_ARGS) != OK) 296 returnCode(ERR); 297 } 298 } 299 } 300 ++depth; 301 } while (found); 302 returnCode(OK); 303} 304 305/* 306 * This function reallocates NCURSES window structures, with no side-effects 307 * such as ungetch(). 308 */ 309NCURSES_EXPORT(int) 310resize_term(int ToLines, int ToCols) 311{ 312 int result = OK EXTRA_ARGS; 313 int was_stolen; 314 315 T((T_CALLED("resize_term(%d,%d) old(%d,%d)"), 316 ToLines, ToCols, 317 screen_lines, screen_columns)); 318 319 if (SP == 0) { 320 returnCode(ERR); 321 } 322 323 _nc_lock_global(windowlist); 324 325 was_stolen = (screen_lines - SP->_lines_avail); 326 if (is_term_resized(ToLines, ToCols)) { 327 int myLines = CurLines = screen_lines; 328 int myCols = CurCols = screen_columns; 329 330#ifdef TRACE 331 if (USE_TRACEF(TRACE_UPDATE)) { 332 show_window_sizes("before"); 333 _nc_unlock_global(tracef); 334 } 335#endif 336 if (ToLines > screen_lines) { 337 increase_size(myLines = ToLines, myCols, was_stolen EXTRA_ARGS); 338 CurLines = myLines; 339 CurCols = myCols; 340 } 341 342 if (ToCols > screen_columns) { 343 increase_size(myLines, myCols = ToCols, was_stolen EXTRA_ARGS); 344 CurLines = myLines; 345 CurCols = myCols; 346 } 347 348 if (ToLines < myLines || 349 ToCols < myCols) { 350 decrease_size(ToLines, ToCols, was_stolen EXTRA_ARGS); 351 } 352 353 screen_lines = lines = ToLines; 354 screen_columns = columns = ToCols; 355 356 SP->_lines_avail = lines - was_stolen; 357 358 if (SP->oldhash) { 359 FreeAndNull(SP->oldhash); 360 } 361 if (SP->newhash) { 362 FreeAndNull(SP->newhash); 363 } 364#ifdef TRACE 365 if (USE_TRACEF(TRACE_UPDATE)) { 366 SET_LINES(ToLines - was_stolen); 367 SET_COLS(ToCols); 368 show_window_sizes("after"); 369 _nc_unlock_global(tracef); 370 } 371#endif 372 } 373 374 /* 375 * Always update LINES, to allow for call from lib_doupdate.c which 376 * needs to have the count adjusted by the stolen (ripped off) lines. 377 */ 378 SET_LINES(ToLines - was_stolen); 379 SET_COLS(ToCols); 380 381 _nc_unlock_global(windowlist); 382 383 returnCode(result); 384} 385 386/* 387 * This function reallocates NCURSES window structures. It is invoked in 388 * response to a SIGWINCH interrupt. Other user-defined windows may also need 389 * to be reallocated. 390 * 391 * Because this performs memory allocation, it should not (in general) be 392 * invoked directly from the signal handler. 393 */ 394NCURSES_EXPORT(int) 395resizeterm(int ToLines, int ToCols) 396{ 397 int result = ERR; 398 399 T((T_CALLED("resizeterm(%d,%d) old(%d,%d)"), 400 ToLines, ToCols, 401 screen_lines, screen_columns)); 402 403 if (SP != 0) { 404 result = OK; 405 SP->_sig_winch = FALSE; 406 407 if (is_term_resized(ToLines, ToCols)) { 408#if USE_SIGWINCH 409 ripoff_t *rop; 410 bool slk_visible = (SP != 0 411 && SP->_slk != 0 412 && !(SP->_slk->hidden)); 413 414 if (slk_visible) { 415 slk_clear(); 416 } 417#endif 418 result = resize_term(ToLines, ToCols); 419 420#if USE_SIGWINCH 421 ungetch(KEY_RESIZE); /* so application can know this */ 422 clearok(curscr, TRUE); /* screen contents are unknown */ 423 424 /* ripped-off lines are a special case: if we did not lengthen 425 * them, we haven't moved them either. repaint them, too. 426 * 427 * for the rest - stdscr and other windows - the client has to 428 * decide which to repaint, since without panels, ncurses does 429 * not know which are really on top. 430 */ 431 for (each_ripoff(rop)) { 432 if (rop->win != stdscr 433 && rop->win != 0 434 && rop->line < 0) { 435 436 if (rop->hook != _nc_slk_initialize) { 437 touchwin(rop->win); 438 wnoutrefresh(rop->win); 439 } 440 } 441 } 442 443 /* soft-keys are a special case: we _know_ how to repaint them */ 444 if (slk_visible) { 445 slk_restore(); 446 slk_touch(); 447 448 slk_refresh(); 449 } 450#endif 451 } 452 } 453 454 returnCode(result); 455} 456