150276Speter/**************************************************************************** 2176187Srafan * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * 350276Speter * * 450276Speter * Permission is hereby granted, free of charge, to any person obtaining a * 550276Speter * copy of this software and associated documentation files (the * 650276Speter * "Software"), to deal in the Software without restriction, including * 750276Speter * without limitation the rights to use, copy, modify, merge, publish, * 850276Speter * distribute, distribute with modifications, sublicense, and/or sell * 950276Speter * copies of the Software, and to permit persons to whom the Software is * 1050276Speter * furnished to do so, subject to the following conditions: * 1150276Speter * * 1250276Speter * The above copyright notice and this permission notice shall be included * 1350276Speter * in all copies or substantial portions of the Software. * 1450276Speter * * 1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2250276Speter * * 2350276Speter * Except as contained in this notice, the name(s) of the above copyright * 2450276Speter * holders shall not be used in advertising or otherwise to promote the * 2550276Speter * sale, use or other dealings in this Software without prior written * 2650276Speter * authorization. * 2750276Speter ****************************************************************************/ 2850276Speter 2950276Speter/**************************************************************************** 30166124Srafan * Author: Thomas E. Dickey * 3150276Speter ****************************************************************************/ 3250276Speter 3350276Speter/* 3450276Speter * This is an extension to the curses library. It provides callers with a hook 3550276Speter * into the NCURSES data to resize windows, primarily for use by programs 3650276Speter * running in an X Window terminal (e.g., xterm). I abstracted this module 3750276Speter * from my application library for NCURSES because it must be compiled with 3850276Speter * the private data structures -- T.Dickey 1995/7/4. 3950276Speter */ 4050276Speter 4150276Speter#include <curses.priv.h> 4250276Speter#include <term.h> 4350276Speter 44184989SrafanMODULE_ID("$Id: resizeterm.c,v 1.34 2008/06/07 13:58:40 tom Exp $") 4550276Speter 46166124Srafan#define stolen_lines (screen_lines - SP->_lines_avail) 47166124Srafan 48174993Srafan/* 49174993Srafan * If we're trying to be reentrant, do not want any local statics. 50174993Srafan */ 51174993Srafan#if USE_REENTRANT 52174993Srafan#define EXTRA_ARGS , CurLines, CurCols 53174993Srafan#define EXTRA_DCLS , int CurLines, int CurCols 54174993Srafan#else 55166124Srafanstatic int current_lines; 56166124Srafanstatic int current_cols; 57174993Srafan#define CurLines current_lines 58174993Srafan#define CurCols current_cols 59174993Srafan#define EXTRA_ARGS /* nothing */ 60174993Srafan#define EXTRA_DCLS /* nothing */ 61174993Srafan#endif 62166124Srafan 63166124Srafan#ifdef TRACE 64166124Srafanstatic void 65166124Srafanshow_window_sizes(const char *name) 66166124Srafan{ 67166124Srafan WINDOWLIST *wp; 68166124Srafan 69184989Srafan _nc_lock_global(curses); 70166124Srafan _tracef("%s resizing: %2d x %2d (%2d x %2d)", name, LINES, COLS, 71166124Srafan screen_lines, screen_columns); 72178866Srafan for (each_window(wp)) { 73166124Srafan _tracef(" window %p is %2ld x %2ld at %2ld,%2ld", 74166124Srafan &(wp->win), 75166124Srafan (long) wp->win._maxy + 1, 76166124Srafan (long) wp->win._maxx + 1, 77166124Srafan (long) wp->win._begy, 78166124Srafan (long) wp->win._begx); 79166124Srafan } 80184989Srafan _nc_unlock_global(curses); 81166124Srafan} 82166124Srafan#endif 83166124Srafan 84176187Srafan/* 85176187Srafan * Return true if the given dimensions do not match the internal terminal 86176187Srafan * structure's size. 87176187Srafan */ 8897049SpeterNCURSES_EXPORT(bool) 8997049Speteris_term_resized(int ToLines, int ToCols) 9097049Speter{ 91166124Srafan T((T_CALLED("is_term_resized(%d, %d)"), ToLines, ToCols)); 92166124Srafan returnCode(ToLines > 0 93166124Srafan && ToCols > 0 94166124Srafan && (ToLines != screen_lines 95166124Srafan || ToCols != screen_columns)); 9697049Speter} 9797049Speter 9850276Speter/* 99176187Srafan */ 100176187Srafanstatic ripoff_t * 101176187Srafanripped_window(WINDOW *win) 102176187Srafan{ 103176187Srafan ripoff_t *result = 0; 104176187Srafan ripoff_t *rop; 105176187Srafan 106176187Srafan if (win != 0) { 107178866Srafan for (each_ripoff(rop)) { 108176187Srafan if (rop->win == win && rop->line != 0) { 109176187Srafan result = rop; 110176187Srafan break; 111176187Srafan } 112176187Srafan } 113176187Srafan } 114176187Srafan return result; 115176187Srafan} 116176187Srafan 117176187Srafan/* 118176187Srafan * Returns the number of lines from the bottom for the beginning of a ripped 119176187Srafan * off window. 120176187Srafan */ 121176187Srafanstatic int 122176187Srafanripped_bottom(WINDOW *win) 123176187Srafan{ 124176187Srafan int result = 0; 125176187Srafan ripoff_t *rop; 126176187Srafan 127176187Srafan if (win != 0) { 128178866Srafan for (each_ripoff(rop)) { 129176187Srafan if (rop->line < 0) { 130176187Srafan result -= rop->line; 131176187Srafan if (rop->win == win) { 132176187Srafan break; 133176187Srafan } 134176187Srafan } 135176187Srafan } 136176187Srafan } 137176187Srafan return result; 138176187Srafan} 139176187Srafan 140176187Srafan/* 141166124Srafan * Return the number of levels of child-windows under the current window. 142166124Srafan */ 143166124Srafanstatic int 144166124Srafanchild_depth(WINDOW *cmp) 145166124Srafan{ 146166124Srafan int depth = 0; 147166124Srafan 148166124Srafan if (cmp != 0) { 149166124Srafan WINDOWLIST *wp; 150166124Srafan 151178866Srafan for (each_window(wp)) { 152166124Srafan WINDOW *tst = &(wp->win); 153166124Srafan if (tst->_parent == cmp) { 154166124Srafan depth = 1 + child_depth(tst); 155166124Srafan break; 156166124Srafan } 157166124Srafan } 158166124Srafan } 159166124Srafan return depth; 160166124Srafan} 161166124Srafan 162166124Srafan/* 163166124Srafan * Return the number of levels of parent-windows above the current window. 164166124Srafan */ 165166124Srafanstatic int 166166124Srafanparent_depth(WINDOW *cmp) 167166124Srafan{ 168166124Srafan int depth = 0; 169166124Srafan 170166124Srafan if (cmp != 0) { 171166124Srafan WINDOW *tst; 172166124Srafan while ((tst = cmp->_parent) != 0) { 173166124Srafan ++depth; 174166124Srafan cmp = tst; 175166124Srafan } 176166124Srafan } 177166124Srafan return depth; 178166124Srafan} 179166124Srafan 180166124Srafan/* 181166124Srafan * FIXME: must adjust position so it's within the parent! 182166124Srafan */ 183166124Srafanstatic int 184174993Srafanadjust_window(WINDOW *win, int ToLines, int ToCols, int stolen EXTRA_DCLS) 185166124Srafan{ 186166124Srafan int result; 187174993Srafan int bottom = CurLines + SP->_topstolen - stolen; 188166124Srafan int myLines = win->_maxy + 1; 189166124Srafan int myCols = win->_maxx + 1; 190176187Srafan ripoff_t *rop = ripped_window(win); 191166124Srafan 192176187Srafan T((T_CALLED("adjust_window(%p,%d,%d)%s depth %d/%d currently %ldx%ld at %ld,%ld"), 193166124Srafan win, ToLines, ToCols, 194176187Srafan (rop != 0) ? " (rip)" : "", 195176187Srafan parent_depth(win), 196176187Srafan child_depth(win), 197166124Srafan (long) getmaxy(win), (long) getmaxx(win), 198176187Srafan (long) getbegy(win) + win->_yoffset, (long) getbegx(win))); 199166124Srafan 200176187Srafan if (rop != 0 && rop->line < 0) { 201176187Srafan /* 202176187Srafan * If it is a ripped-off window at the bottom of the screen, simply 203176187Srafan * move it to the same relative position. 204176187Srafan */ 205176187Srafan win->_begy = ToLines - ripped_bottom(win) - 0 - win->_yoffset; 206176187Srafan } else if (win->_begy >= bottom) { 207176187Srafan /* 208176187Srafan * If it is below the bottom of the new screen, move up by the same 209176187Srafan * amount that the screen shrank. 210176187Srafan */ 211174993Srafan win->_begy += (ToLines - CurLines); 212166124Srafan } else { 213176187Srafan if (myLines == (CurLines - stolen) 214176187Srafan && ToLines != CurLines) { 215166124Srafan myLines = ToLines - stolen; 216176187Srafan } else if (myLines == CurLines 217176187Srafan && ToLines != CurLines) { 218166124Srafan myLines = ToLines; 219176187Srafan } 220166124Srafan } 221166124Srafan 222176187Srafan if (myLines > ToLines) { 223166124Srafan myLines = ToLines; 224176187Srafan } 225166124Srafan 226166124Srafan if (myCols > ToCols) 227166124Srafan myCols = ToCols; 228166124Srafan 229174993Srafan if (myCols == CurCols 230174993Srafan && ToCols != CurCols) 231166124Srafan myCols = ToCols; 232166124Srafan 233166124Srafan result = wresize(win, myLines, myCols); 234166124Srafan returnCode(result); 235166124Srafan} 236166124Srafan 237166124Srafan/* 238166124Srafan * If we're decreasing size, recursively search for windows that have no 239166124Srafan * children, decrease those to fit, then decrease the containing window, etc. 240166124Srafan */ 241166124Srafanstatic int 242174993Srafandecrease_size(int ToLines, int ToCols, int stolen EXTRA_DCLS) 243166124Srafan{ 244166124Srafan bool found; 245166124Srafan int depth = 0; 246166124Srafan WINDOWLIST *wp; 247166124Srafan 248166124Srafan T((T_CALLED("decrease_size(%d, %d)"), ToLines, ToCols)); 249166124Srafan 250166124Srafan do { 251166124Srafan found = FALSE; 252166124Srafan TR(TRACE_UPDATE, ("decreasing size of windows to %dx%d, depth=%d", 253166124Srafan ToLines, ToCols, depth)); 254178866Srafan for (each_window(wp)) { 255166124Srafan WINDOW *win = &(wp->win); 256166124Srafan 257166124Srafan if (!(win->_flags & _ISPAD)) { 258166124Srafan if (child_depth(win) == depth) { 259166124Srafan found = TRUE; 260174993Srafan if (adjust_window(win, ToLines, ToCols, 261174993Srafan stolen EXTRA_ARGS) != OK) 262166124Srafan returnCode(ERR); 263166124Srafan } 264166124Srafan } 265166124Srafan } 266166124Srafan ++depth; 267166124Srafan } while (found); 268166124Srafan returnCode(OK); 269166124Srafan} 270166124Srafan 271166124Srafan/* 272166124Srafan * If we're increasing size, recursively search for windows that have no 273166124Srafan * parent, increase those to fit, then increase the contained window, etc. 274166124Srafan */ 275166124Srafanstatic int 276174993Srafanincrease_size(int ToLines, int ToCols, int stolen EXTRA_DCLS) 277166124Srafan{ 278166124Srafan bool found; 279166124Srafan int depth = 0; 280166124Srafan WINDOWLIST *wp; 281166124Srafan 282166124Srafan T((T_CALLED("increase_size(%d, %d)"), ToLines, ToCols)); 283166124Srafan 284166124Srafan do { 285166124Srafan found = FALSE; 286166124Srafan TR(TRACE_UPDATE, ("increasing size of windows to %dx%d, depth=%d", 287166124Srafan ToLines, ToCols, depth)); 288178866Srafan for (each_window(wp)) { 289166124Srafan WINDOW *win = &(wp->win); 290166124Srafan 291166124Srafan if (!(win->_flags & _ISPAD)) { 292166124Srafan if (parent_depth(win) == depth) { 293166124Srafan found = TRUE; 294174993Srafan if (adjust_window(win, ToLines, ToCols, 295174993Srafan stolen EXTRA_ARGS) != OK) 296166124Srafan returnCode(ERR); 297166124Srafan } 298166124Srafan } 299166124Srafan } 300166124Srafan ++depth; 301166124Srafan } while (found); 302166124Srafan returnCode(OK); 303166124Srafan} 304166124Srafan 305166124Srafan/* 30697049Speter * This function reallocates NCURSES window structures, with no side-effects 30797049Speter * such as ungetch(). 30850276Speter */ 30976726SpeterNCURSES_EXPORT(int) 31097049Speterresize_term(int ToLines, int ToCols) 31150276Speter{ 312174993Srafan int result = OK EXTRA_ARGS; 313174993Srafan int was_stolen; 31450276Speter 31597049Speter T((T_CALLED("resize_term(%d,%d) old(%d,%d)"), 31676726Speter ToLines, ToCols, 31776726Speter screen_lines, screen_columns)); 31850276Speter 319174993Srafan if (SP == 0) { 320174993Srafan returnCode(ERR); 321174993Srafan } 322174993Srafan 323184989Srafan _nc_lock_global(curses); 324174993Srafan 325174993Srafan was_stolen = (screen_lines - SP->_lines_avail); 32697049Speter if (is_term_resized(ToLines, ToCols)) { 327174993Srafan int myLines = CurLines = screen_lines; 328174993Srafan int myCols = CurCols = screen_columns; 32950276Speter 330166124Srafan#ifdef TRACE 331174993Srafan if (USE_TRACEF(TRACE_UPDATE)) { 332166124Srafan show_window_sizes("before"); 333174993Srafan _nc_unlock_global(tracef); 334174993Srafan } 335166124Srafan#endif 336166124Srafan if (ToLines > screen_lines) { 337174993Srafan increase_size(myLines = ToLines, myCols, was_stolen EXTRA_ARGS); 338174993Srafan CurLines = myLines; 339174993Srafan CurCols = myCols; 340166124Srafan } 34150276Speter 342166124Srafan if (ToCols > screen_columns) { 343174993Srafan increase_size(myLines, myCols = ToCols, was_stolen EXTRA_ARGS); 344174993Srafan CurLines = myLines; 345174993Srafan CurCols = myCols; 346166124Srafan } 34750276Speter 348166124Srafan if (ToLines < myLines || 349166124Srafan ToCols < myCols) { 350174993Srafan decrease_size(ToLines, ToCols, was_stolen EXTRA_ARGS); 35176726Speter } 35250276Speter 35376726Speter screen_lines = lines = ToLines; 35476726Speter screen_columns = columns = ToCols; 35550276Speter 356166124Srafan SP->_lines_avail = lines - was_stolen; 35750276Speter 35876726Speter if (SP->oldhash) { 35976726Speter FreeAndNull(SP->oldhash); 36050276Speter } 36176726Speter if (SP->newhash) { 36276726Speter FreeAndNull(SP->newhash); 36376726Speter } 364166124Srafan#ifdef TRACE 365174993Srafan if (USE_TRACEF(TRACE_UPDATE)) { 366174993Srafan SET_LINES(ToLines - was_stolen); 367174993Srafan SET_COLS(ToCols); 368166124Srafan show_window_sizes("after"); 369174993Srafan _nc_unlock_global(tracef); 370166124Srafan } 371166124Srafan#endif 37276726Speter } 37350276Speter 37476726Speter /* 37576726Speter * Always update LINES, to allow for call from lib_doupdate.c which 37676726Speter * needs to have the count adjusted by the stolen (ripped off) lines. 37776726Speter */ 378174993Srafan SET_LINES(ToLines - was_stolen); 379174993Srafan SET_COLS(ToCols); 38050276Speter 381184989Srafan _nc_unlock_global(curses); 382174993Srafan 383166124Srafan returnCode(result); 38450276Speter} 38597049Speter 38697049Speter/* 38797049Speter * This function reallocates NCURSES window structures. It is invoked in 38897049Speter * response to a SIGWINCH interrupt. Other user-defined windows may also need 38997049Speter * to be reallocated. 39097049Speter * 39197049Speter * Because this performs memory allocation, it should not (in general) be 39297049Speter * invoked directly from the signal handler. 39397049Speter */ 39497049SpeterNCURSES_EXPORT(int) 39597049Speterresizeterm(int ToLines, int ToCols) 39697049Speter{ 397174993Srafan int result = ERR; 39897049Speter 39997049Speter T((T_CALLED("resizeterm(%d,%d) old(%d,%d)"), 40097049Speter ToLines, ToCols, 40197049Speter screen_lines, screen_columns)); 40297049Speter 403174993Srafan if (SP != 0) { 404174993Srafan result = OK; 405174993Srafan SP->_sig_winch = FALSE; 40697049Speter 407174993Srafan if (is_term_resized(ToLines, ToCols)) { 408176187Srafan#if USE_SIGWINCH 409176187Srafan ripoff_t *rop; 410176187Srafan bool slk_visible = (SP != 0 411176187Srafan && SP->_slk != 0 412176187Srafan && !(SP->_slk->hidden)); 413174993Srafan 414176187Srafan if (slk_visible) { 415176187Srafan slk_clear(); 416176187Srafan } 417176187Srafan#endif 418176187Srafan result = resize_term(ToLines, ToCols); 419176187Srafan 42097049Speter#if USE_SIGWINCH 421184989Srafan _nc_ungetch(SP, KEY_RESIZE); /* so application can know this */ 422174993Srafan clearok(curscr, TRUE); /* screen contents are unknown */ 423176187Srafan 424176187Srafan /* ripped-off lines are a special case: if we did not lengthen 425176187Srafan * them, we haven't moved them either. repaint them, too. 426176187Srafan * 427176187Srafan * for the rest - stdscr and other windows - the client has to 428176187Srafan * decide which to repaint, since without panels, ncurses does 429176187Srafan * not know which are really on top. 430176187Srafan */ 431178866Srafan for (each_ripoff(rop)) { 432176187Srafan if (rop->win != stdscr 433176187Srafan && rop->win != 0 434176187Srafan && rop->line < 0) { 435176187Srafan 436176187Srafan if (rop->hook != _nc_slk_initialize) { 437176187Srafan touchwin(rop->win); 438176187Srafan wnoutrefresh(rop->win); 439176187Srafan } 440176187Srafan } 441176187Srafan } 442176187Srafan 443176187Srafan /* soft-keys are a special case: we _know_ how to repaint them */ 444176187Srafan if (slk_visible) { 445176187Srafan slk_restore(); 446176187Srafan slk_touch(); 447176187Srafan 448176187Srafan slk_refresh(); 449176187Srafan } 45097049Speter#endif 451174993Srafan } 45297049Speter } 45397049Speter 45497049Speter returnCode(result); 45597049Speter} 456