Back to index

tetex-bin  3.0
resizeterm.c
Go to the documentation of this file.
00001 /****************************************************************************
00002  * Copyright (c) 1998-2002,2004 Free Software Foundation, Inc.              *
00003  *                                                                          *
00004  * Permission is hereby granted, free of charge, to any person obtaining a  *
00005  * copy of this software and associated documentation files (the            *
00006  * "Software"), to deal in the Software without restriction, including      *
00007  * without limitation the rights to use, copy, modify, merge, publish,      *
00008  * distribute, distribute with modifications, sublicense, and/or sell       *
00009  * copies of the Software, and to permit persons to whom the Software is    *
00010  * furnished to do so, subject to the following conditions:                 *
00011  *                                                                          *
00012  * The above copyright notice and this permission notice shall be included  *
00013  * in all copies or substantial portions of the Software.                   *
00014  *                                                                          *
00015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
00016  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
00017  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
00018  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
00019  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
00020  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
00021  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
00022  *                                                                          *
00023  * Except as contained in this notice, the name(s) of the above copyright   *
00024  * holders shall not be used in advertising or otherwise to promote the     *
00025  * sale, use or other dealings in this Software without prior written       *
00026  * authorization.                                                           *
00027  ****************************************************************************/
00028 
00029 /****************************************************************************
00030  *  Author: Thomas E. Dickey                                                *
00031  ****************************************************************************/
00032 
00033 /*
00034  * This is an extension to the curses library.  It provides callers with a hook
00035  * into the NCURSES data to resize windows, primarily for use by programs
00036  * running in an X Window terminal (e.g., xterm).  I abstracted this module
00037  * from my application library for NCURSES because it must be compiled with
00038  * the private data structures -- T.Dickey 1995/7/4.
00039  */
00040 
00041 #include <curses.priv.h>
00042 #include <term.h>
00043 
00044 MODULE_ID("$Id: resizeterm.c,v 1.17 2004/07/31 20:24:38 tom Exp $")
00045 
00046 #define stolen_lines (screen_lines - SP->_lines_avail)
00047 
00048 static int current_lines;
00049 static int current_cols;
00050 
00051 #ifdef TRACE
00052 static void
00053 show_window_sizes(const char *name)
00054 {
00055     WINDOWLIST *wp;
00056 
00057     _tracef("%s resizing: %2d x %2d (%2d x %2d)", name, LINES, COLS,
00058            screen_lines, screen_columns);
00059     for (wp = _nc_windows; wp != 0; wp = wp->next) {
00060        _tracef("  window %p is %2d x %2d at %2d,%2d",
00061               &(wp->win),
00062               wp->win._maxy + 1,
00063               wp->win._maxx + 1,
00064               wp->win._begy,
00065               wp->win._begx);
00066     }
00067 }
00068 #endif
00069 
00070 NCURSES_EXPORT(bool)
00071 is_term_resized(int ToLines, int ToCols)
00072 {
00073     T((T_CALLED("is_term_resized(%d, %d)"), ToLines, ToCols));
00074     returnCode(ToLines > 0
00075               && ToCols > 0
00076               && (ToLines != screen_lines
00077                  || ToCols != screen_columns));
00078 }
00079 
00080 /*
00081  * Return the number of levels of child-windows under the current window.
00082  */
00083 static int
00084 child_depth(WINDOW *cmp)
00085 {
00086     int depth = 0;
00087 
00088     if (cmp != 0) {
00089        WINDOWLIST *wp;
00090 
00091        for (wp = _nc_windows; wp != 0; wp = wp->next) {
00092            WINDOW *tst = &(wp->win);
00093            if (tst->_parent == cmp) {
00094               depth = 1 + child_depth(tst);
00095               break;
00096            }
00097        }
00098     }
00099     return depth;
00100 }
00101 
00102 /*
00103  * Return the number of levels of parent-windows above the current window.
00104  */
00105 static int
00106 parent_depth(WINDOW *cmp)
00107 {
00108     int depth = 0;
00109 
00110     if (cmp != 0) {
00111        WINDOW *tst;
00112        while ((tst = cmp->_parent) != 0) {
00113            ++depth;
00114            cmp = tst;
00115        }
00116     }
00117     return depth;
00118 }
00119 
00120 /*
00121  * FIXME: must adjust position so it's within the parent!
00122  */
00123 static int
00124 adjust_window(WINDOW *win, int ToLines, int ToCols, int stolen)
00125 {
00126     int result;
00127     int bottom = current_lines + SP->_topstolen - stolen;
00128     int myLines = win->_maxy + 1;
00129     int myCols = win->_maxx + 1;
00130 
00131     T((T_CALLED("adjust_window(%p,%d,%d) currently %dx%d at %d,%d"),
00132        win, ToLines, ToCols,
00133        getmaxy(win), getmaxx(win),
00134        getbegy(win), getbegx(win)));
00135 
00136     if (win->_begy >= bottom) {
00137        win->_begy += (ToLines - current_lines);
00138     } else {
00139        if (myLines == current_lines - stolen
00140            && ToLines != current_lines)
00141            myLines = ToLines - stolen;
00142        else if (myLines == current_lines
00143                && ToLines != current_lines)
00144            myLines = ToLines;
00145     }
00146 
00147     if (myLines > ToLines)
00148        myLines = ToLines;
00149 
00150     if (myCols > ToCols)
00151        myCols = ToCols;
00152 
00153     if (myLines == current_lines
00154        && ToLines != current_lines)
00155        myLines = ToLines;
00156 
00157     if (myCols == current_cols
00158        && ToCols != current_cols)
00159        myCols = ToCols;
00160 
00161     result = wresize(win, myLines, myCols);
00162     returnCode(result);
00163 }
00164 
00165 /*
00166  * If we're decreasing size, recursively search for windows that have no
00167  * children, decrease those to fit, then decrease the containing window, etc.
00168  */
00169 static int
00170 decrease_size(int ToLines, int ToCols, int stolen)
00171 {
00172     bool found;
00173     int depth = 0;
00174     WINDOWLIST *wp;
00175 
00176     T((T_CALLED("decrease_size(%d, %d)"), ToLines, ToCols));
00177 
00178     do {
00179        found = FALSE;
00180        TR(TRACE_UPDATE, ("decreasing size of windows to %dx%d, depth=%d",
00181                        ToLines, ToCols, depth));
00182        for (wp = _nc_windows; wp != 0; wp = wp->next) {
00183            WINDOW *win = &(wp->win);
00184 
00185            if (!(win->_flags & _ISPAD)) {
00186               if (child_depth(win) == depth) {
00187                   found = TRUE;
00188                   if (adjust_window(win, ToLines, ToCols, stolen) != OK)
00189                      returnCode(ERR);
00190               }
00191            }
00192        }
00193        ++depth;
00194     } while (found);
00195     returnCode(OK);
00196 }
00197 
00198 /*
00199  * If we're increasing size, recursively search for windows that have no
00200  * parent, increase those to fit, then increase the contained window, etc.
00201  */
00202 static int
00203 increase_size(int ToLines, int ToCols, int stolen)
00204 {
00205     bool found;
00206     int depth = 0;
00207     WINDOWLIST *wp;
00208 
00209     T((T_CALLED("increase_size(%d, %d)"), ToLines, ToCols));
00210 
00211     do {
00212        found = FALSE;
00213        TR(TRACE_UPDATE, ("increasing size of windows to %dx%d, depth=%d",
00214                        ToLines, ToCols, depth));
00215        for (wp = _nc_windows; wp != 0; wp = wp->next) {
00216            WINDOW *win = &(wp->win);
00217 
00218            if (!(win->_flags & _ISPAD)) {
00219               if (parent_depth(win) == depth) {
00220                   found = TRUE;
00221                   if (adjust_window(win, ToLines, ToCols, stolen) != OK)
00222                      returnCode(ERR);
00223               }
00224            }
00225        }
00226        ++depth;
00227     } while (found);
00228     returnCode(OK);
00229 }
00230 
00231 /*
00232  * This function reallocates NCURSES window structures, with no side-effects
00233  * such as ungetch().
00234  */
00235 NCURSES_EXPORT(int)
00236 resize_term(int ToLines, int ToCols)
00237 {
00238     int result = OK;
00239     int was_stolen = (screen_lines - SP->_lines_avail);
00240 
00241     T((T_CALLED("resize_term(%d,%d) old(%d,%d)"),
00242        ToLines, ToCols,
00243        screen_lines, screen_columns));
00244 
00245     if (is_term_resized(ToLines, ToCols)) {
00246        int myLines = current_lines = screen_lines;
00247        int myCols = current_cols = screen_columns;
00248 
00249 #ifdef TRACE
00250        if (_nc_tracing & TRACE_UPDATE)
00251            show_window_sizes("before");
00252 #endif
00253        if (ToLines > screen_lines) {
00254            increase_size(myLines = ToLines, myCols, was_stolen);
00255            current_lines = myLines;
00256            current_cols = myCols;
00257        }
00258 
00259        if (ToCols > screen_columns) {
00260            increase_size(myLines, myCols = ToCols, was_stolen);
00261            current_lines = myLines;
00262            current_cols = myCols;
00263        }
00264 
00265        if (ToLines < myLines ||
00266            ToCols < myCols) {
00267            decrease_size(ToLines, ToCols, was_stolen);
00268        }
00269 
00270        screen_lines = lines = ToLines;
00271        screen_columns = columns = ToCols;
00272 
00273        SP->_lines_avail = lines - was_stolen;
00274 
00275        if (SP->oldhash) {
00276            FreeAndNull(SP->oldhash);
00277        }
00278        if (SP->newhash) {
00279            FreeAndNull(SP->newhash);
00280        }
00281 #ifdef TRACE
00282        if (_nc_tracing & TRACE_UPDATE) {
00283            LINES = ToLines - was_stolen;
00284            COLS = ToCols;
00285            show_window_sizes("after");
00286        }
00287 #endif
00288     }
00289 
00290     /*
00291      * Always update LINES, to allow for call from lib_doupdate.c which
00292      * needs to have the count adjusted by the stolen (ripped off) lines.
00293      */
00294     LINES = ToLines - was_stolen;
00295     COLS = ToCols;
00296 
00297     returnCode(result);
00298 }
00299 
00300 /*
00301  * This function reallocates NCURSES window structures.  It is invoked in
00302  * response to a SIGWINCH interrupt.  Other user-defined windows may also need
00303  * to be reallocated.
00304  *
00305  * Because this performs memory allocation, it should not (in general) be
00306  * invoked directly from the signal handler.
00307  */
00308 NCURSES_EXPORT(int)
00309 resizeterm(int ToLines, int ToCols)
00310 {
00311     int result = OK;
00312 
00313     SP->_sig_winch = FALSE;
00314 
00315     T((T_CALLED("resizeterm(%d,%d) old(%d,%d)"),
00316        ToLines, ToCols,
00317        screen_lines, screen_columns));
00318 
00319     if (is_term_resized(ToLines, ToCols)) {
00320 
00321 #if USE_SIGWINCH
00322        ungetch(KEY_RESIZE); /* so application can know this */
00323        clearok(curscr, TRUE);      /* screen contents are unknown */
00324 #endif
00325 
00326        result = resize_term(ToLines, ToCols);
00327     }
00328 
00329     returnCode(result);
00330 }