diff options
author | Axel Beckert <abe@deuxchevaux.org> | 2011-09-03 14:05:19 +0200 |
---|---|---|
committer | Axel Beckert <abe@deuxchevaux.org> | 2011-09-03 14:05:19 +0200 |
commit | 0636e9ecb5a32db4d4520f50a20652faa825feaf (patch) | |
tree | b94df9221e8ae0de0dc3afac301d5b63b136a7b4 /resize.c | |
download | screen-0636e9ecb5a32db4d4520f50a20652faa825feaf.tar.gz |
Imported Upstream version 3.7.2upstream/3.7.2
Diffstat (limited to 'resize.c')
-rw-r--r-- | resize.c | 750 |
1 files changed, 750 insertions, 0 deletions
diff --git a/resize.c b/resize.c new file mode 100644 index 0000000..9a21c81 --- /dev/null +++ b/resize.c @@ -0,0 +1,750 @@ +/* Copyright (c) 1993 + * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) + * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) + * Copyright (c) 1987 Oliver Laumann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING); if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + **************************************************************** + */ + +#include "rcs.h" +RCS_ID("$Id: resize.c,v 1.5 1994/05/31 12:32:47 mlschroe Exp $ FAU") + +#include <sys/types.h> +#include <signal.h> +#ifndef sun +#include <sys/ioctl.h> +#endif + +#ifdef ISC +# include <sys/tty.h> +# include <sys/sioctl.h> +# include <sys/pty.h> +#endif + +#include "config.h" +#include "screen.h" +#include "extern.h" + +static void CheckMaxSize __P((int)); +static void FreeMline __P((struct mline *)); +static int AllocMline __P((struct mline *ml, int)); +static void MakeBlankLine __P((char *, int)); + +extern struct display *display, *displays; +extern char *blank, *null; +extern struct mline mline_blank, mline_null, mline_old; +extern struct win *windows; +extern int Z0width, Z1width; + +#ifdef NETHACK +extern int nethackflag; +#endif + +#if defined(TIOCGWINSZ) || defined(TIOCSWINSZ) + struct winsize glwz; +#endif + +static struct mline mline_zero = { + (char *)0, + (char *)0, + (char *)0 +#ifdef COLOR + ,(char *)0 +#endif +}; + +/* + * ChangeFlag: 0: try to modify no window + * 1: modify fore (and try to modify no D_other) + redisplay + * 2: modify all windows + * + * Note: Activate() is only called if change_flag == 1 + * i.e. on a WINCH event + */ + +void +CheckScreenSize(change_flag) +int change_flag; +{ + int wi, he; + struct win *p; + struct layer *oldlay; + + if (display == 0) + { + debug("CheckScreenSize: No display -> no check.\n"); + return; + } + oldlay = D_lay; +#ifdef TIOCGWINSZ + if (ioctl(D_userfd, TIOCGWINSZ, (char *)&glwz) != 0) + { + debug2("CheckScreenSize: ioctl(%d, TIOCGWINSZ) errno %d\n", D_userfd, errno); + wi = D_CO; + he = D_LI; + } + else + { + wi = glwz.ws_col; + he = glwz.ws_row; + if (wi == 0) + wi = D_CO; + if (he == 0) + he = D_LI; + } +#else + wi = D_CO; + he = D_LI; +#endif + + debug2("CheckScreenSize: screen is (%d,%d)\n", wi, he); + + if (change_flag == 2) + { + debug("Trying to adapt all windows (-A)\n"); + for (p = windows; p; p = p->w_next) + if (p->w_display == 0 || p->w_display == display) + ChangeWindowSize(p, wi, he, p->w_histheight); + } + if (D_width == wi && D_height == he) + { + debug("CheckScreenSize: No change -> return.\n"); + return; + } + ChangeScreenSize(wi, he, change_flag); + if (change_flag == 1) + Activate(D_fore ? D_fore->w_norefresh : 0); + if (D_lay != oldlay) + { +#ifdef NETHACK + if (nethackflag) + Msg(0, "KAABLAMM!!! You triggered a land mine!"); + else +#endif + Msg(0, "Aborted because of window size change."); + } +} + +void +ChangeScreenSize(wi, he, change_fore) +int wi, he; +int change_fore; +{ + struct win *p; + int wwi; + + if (D_width == wi && D_height == he) + { + debug("ChangeScreenSize: no change\n"); + return; + } + debug2("ChangeScreenSize from (%d,%d) ", D_width, D_height); + debug3("to (%d,%d) (change_fore: %d)\n",wi, he, change_fore); + D_width = wi; + D_height = he; + + CheckMaxSize(wi); + if (D_CWS) + { + D_defwidth = D_CO; + D_defheight = D_LI; + } + else + { + if (D_CZ0 && (wi == Z0width || wi == Z1width) && + (D_CO == Z0width || D_CO == Z1width)) + D_defwidth = D_CO; + else + D_defwidth = wi; + D_defheight = he; + } + debug2("Default size: (%d,%d)\n", D_defwidth, D_defheight); + if (change_fore) + DoResize(wi, he); + if (D_CWS == NULL && displays->d_next == 0) + { + /* adapt all windows - to be removed ? */ + for (p = windows; p; p = p->w_next) + { + debug1("Trying to change window %d.\n", p->w_number); + wwi = wi; + if (D_CZ0 && (wi == Z0width || wi == Z1width)) + { + if (p->w_width > (Z0width + Z1width) / 2) + wwi = Z0width; + else + wwi = Z1width; + } + ChangeWindowSize(p, wwi, he, p->w_histheight); + } + } +} + +void +DoResize(wi, he) +int wi, he; +{ + struct layer *oldlay; + int q = 0; + + for(;;) + { + oldlay = D_lay; + for (; D_lay; D_lay = D_lay->l_next) + { + D_layfn = D_lay->l_layfn; + if ((q = Resize(wi, he))) + break; + } + D_lay = oldlay; + D_layfn = D_lay->l_layfn; + if (q == 0) + break; + ExitOverlayPage(); + } +} + + +static void +FreeMline(ml) +struct mline *ml; +{ + if (ml->image) + free(ml->image); + if (ml->attr && ml->attr != null) + free(ml->attr); + if (ml->font && ml->font != null) + free(ml->font); +#ifdef COLOR + if (ml->color && ml->color != null) + free(ml->color); +#endif + *ml = mline_zero; +} + +static int +AllocMline(ml, w) +struct mline *ml; +int w; +{ + ml->image = malloc(w); + ml->attr = null; + ml->font = null; +#ifdef COLOR + ml->color = null; +#endif + if (ml->image == 0) + return -1; + return 0; +} + + +static int +BcopyMline(mlf, xf, mlt, xt, l, w) +struct mline *mlf, *mlt; +int xf, xt, l, w; +{ + int r = 0; + + bcopy(mlf->image + xf, mlt->image + xt, l); + if (mlf->attr != null && mlt->attr == null) + { + if ((mlt->attr = malloc(w)) == 0) + mlt->attr = null, r = -1; + bzero(mlt->attr, w); + } + if (mlt->attr != null) + bcopy(mlf->attr + xf, mlt->attr + xt, l); + if (mlf->font != null && mlt->font == null) + { + if ((mlt->font = malloc(w)) == 0) + mlt->font = null, r = -1; + bzero(mlt->font, w); + } + if (mlt->font != null) + bcopy(mlf->font + xf, mlt->font + xt, l); +#ifdef COLOR + if (mlf->color != null && mlt->color == null) + { + if ((mlt->color = malloc(w)) == 0) + mlt->color = null, r = -1; + bzero(mlt->color, w); + } + if (mlt->color != null) + bcopy(mlf->color + xf, mlt->color + xt, l); +#endif + return r; +} + + +static int maxwidth; + +static void +CheckMaxSize(wi) +int wi; +{ + char *oldnull = null; + struct win *p; + int i; + struct mline *ml; + + wi = ((wi + 1) + 255) & ~255; + if (wi <= maxwidth) + return; + maxwidth = wi; + debug1("New maxwidth: %d\n", maxwidth); + if (blank == 0) + blank = malloc((unsigned) maxwidth); + else + blank = xrealloc(blank, maxwidth); + if (null == 0) + null = malloc((unsigned) maxwidth); + else + null = xrealloc(null, maxwidth); + if (mline_old.image == 0) + mline_old.image = malloc((unsigned) maxwidth); + else + mline_old.image = xrealloc(mline_old.image, maxwidth); + if (mline_old.attr == 0) + mline_old.attr = malloc((unsigned) maxwidth); + else + mline_old.attr = xrealloc(mline_old.attr, maxwidth); + if (mline_old.font == 0) + mline_old.font = malloc((unsigned) maxwidth); + else + mline_old.font = xrealloc(mline_old.font, maxwidth); +#ifdef COLOR + if (mline_old.color == 0) + mline_old.color = malloc((unsigned) maxwidth); + else + mline_old.color = xrealloc(mline_old.color, maxwidth); + if (!(blank && null && mline_old.image && mline_old.attr + && mline_old.font && mline_old.color)) + { + Panic(0, "Out of memory -> Game over!!"); + /*NOTREACHED*/ + } +#else + if (!(blank && null && mline_old.image && mline_old.attr + && mline_old.font)) + { + Panic(0, "Out of memory -> Game over!!"); + /*NOTREACHED*/ + } +#endif + MakeBlankLine(blank, maxwidth); + bzero(null, maxwidth); + + mline_blank.image = blank; + mline_blank.attr = null; + mline_blank.font = null; + mline_null.image = null; + mline_null.attr = null; + mline_null.font = null; +#ifdef COLOR + mline_blank.color = null; + mline_null.color = null; +#endif + + /* We have to run through all windows to substitute + * the null references. + */ + for (p = windows; p; p = p->w_next) + { + ml = p->w_mlines; + for (i = 0; i < p->w_height; i++, ml++) + { + if (ml->attr == oldnull) + ml->attr = null; + if (ml->font == oldnull) + ml->font = null; +#ifdef COLOR + if (ml->color== oldnull) + ml->color= null; +#endif + } +#ifdef COPY_PASTE + ml = p->w_hlines; + for (i = 0; i < p->w_histheight; i++, ml++) + { + if (ml->attr == oldnull) + ml->attr = null; + if (ml->font == oldnull) + ml->font = null; +# ifdef COLOR + if (ml->color== oldnull) + ml->color= null; +# endif + } +#endif + } +} + + +char * +xrealloc(mem, len) +char *mem; +int len; +{ + register char *nmem; + + if ((nmem = realloc(mem, len))) + return nmem; + free(mem); + return (char *)0; +} + +static void +MakeBlankLine(p, n) +register char *p; +register int n; +{ + while (n--) + *p++ = ' '; +} + + + + +#ifdef COPY_PASTE + +#define OLDWIN(y) ((y < p->w_histheight) \ + ? &p->w_hlines[(p->w_histidx + y) % p->w_histheight] \ + : &p->w_mlines[y - p->w_histheight]) + +#define NEWWIN(y) ((y < hi) ? &nhlines[y] : &nmlines[y - hi]) + +#else + +#define OLDWIN(y) (&p->w_mlines[y]) +#define NEWWIN(y) (&nmlines[y]) + +#endif + + +int +ChangeWindowSize(p, wi, he, hi) +struct win *p; +int wi, he, hi; +{ + struct mline *mlf = 0, *mlt = 0, *ml, *nmlines, *nhlines; + int fy, ty, l, lx, lf, lt, yy, oty, addone; + int ncx, ncy, naka, t; + + if (wi == 0) + he = hi = 0; + + if (p->w_width == wi && p->w_height == he && p->w_histheight == hi) + { + debug("ChangeWindowSize: No change.\n"); + return 0; + } + + CheckMaxSize(wi); + + /* just in case ... */ + if (wi && (p->w_width != wi || p->w_height != he) && p->w_lay != &p->w_winlay) + { + debug("ChangeWindowSize: No resize because of overlay?\n"); + return -1; + } + + debug("ChangeWindowSize"); + debug3(" from (%d,%d)+%d", p->w_width, p->w_height, p->w_histheight); + debug3(" to(%d,%d)+%d\n", wi, he, hi); + + fy = p->w_histheight + p->w_height - 1; + ty = hi + he - 1; + + nmlines = nhlines = 0; + ncx = 0; + ncy = 0; + naka = 0; + + if (wi) + { + if (wi != p->w_width || he != p->w_height) + { + if ((nmlines = (struct mline *)calloc(he, sizeof(struct mline))) == 0) + { + KillWindow(p); + Msg(0, strnomem); + return -1; + } + } + else + { + debug1("image stays the same: %d lines\n", he); + nmlines = p->w_mlines; + fy -= he; + ty -= he; + ncx = p->w_x; + ncy = p->w_y; + naka = p->w_autoaka; + } + } +#ifdef COPY_PASTE + if (hi) + { + if ((nhlines = (struct mline *)calloc(hi, sizeof(struct mline))) == 0) + { + Msg(0, "No memory for history buffer - turned off"); + hi = 0; + ty = he - 1; + } + } +#endif + + /* special case: cursor is at magic margin position */ + addone = 0; + if (p->w_width && p->w_x == p->w_width) + { + debug2("Special addone case: %d %d\n", p->w_x, p->w_y); + addone = 1; + p->w_x--; + } + + debug2("fy %d ty %d\n", fy, ty); + if (fy >= 0) + mlf = OLDWIN(fy); + if (ty >= 0) + mlt = NEWWIN(ty); + + while (fy >= 0 && ty >= 0) + { + if (p->w_width == wi) + { + /* here is a simple shortcut: just copy over */ + *mlt = *mlf; + *mlf = mline_zero; + if (fy == p->w_y + p->w_histheight) + { + ncx = p->w_x + addone; + ncy = ty - hi >= 0 ? ty - hi : 0; + } + if (p->w_autoaka > 0 && fy == p->w_autoaka - 1 + p->w_histheight) + naka = ty - hi >= 0 ? 1 + ty - hi : 0; + if (--fy >= 0) + mlf = OLDWIN(fy); + if (--ty >= 0) + mlt = NEWWIN(ty); + continue; + } + + /* calculate lenght */ + for (l = p->w_width - 1; l > 0; l--) + if (mlf->image[l] != ' ' || mlf->attr[l]) + break; + if (fy == p->w_y + p->w_histheight && l < p->w_x) + l = p->w_x; /* cursor is non blank */ + l++; + lf = l; + + /* add wrapped lines to length */ + for (yy = fy - 1; yy >= 0; yy--) + { + ml = OLDWIN(yy); + if (ml->image[p->w_width] == ' ') + break; + l += p->w_width; + } + + /* rewrap lines */ + lt = (l - 1) % wi + 1; /* lf is set above */ + oty = ty; + while (l > 0 && fy >= 0 && ty >= 0) + { + lx = lt > lf ? lf : lt; + if (mlt->image == 0) + { + if (AllocMline(mlt, wi + 1)) + goto nomem; + MakeBlankLine(mlt->image + lt, wi - lt); + mlt->image[wi] = ((oty == ty) ? ' ' : 0); + } + if (BcopyMline(mlf, lf - lx, mlt, lt - lx, lx, wi + 1)) + goto nomem; + + /* did we copy the cursor ? */ + if (fy == p->w_y + p->w_histheight && lf - lx <= p->w_x && lf > p->w_x) + { + ncx = p->w_x + lt - lf + addone; + ncy = ty - hi >= 0 ? ty - hi : 0; + } + /* did we copy autoaka line ? */ + if (p->w_autoaka > 0 && fy == p->w_autoaka - 1 + p->w_histheight && lf - lx <= 0) + naka = ty - hi >= 0 ? 1 + ty - hi : 0; + + lf -= lx; + lt -= lx; + l -= lx; + if (lf == 0) + { + FreeMline(mlf); + lf = p->w_width; + if (--fy >= 0) + mlf = OLDWIN(fy); + } + if (lt == 0) + { + lt = wi; + if (--ty >= 0) + mlt = NEWWIN(ty); + } + } + ASSERT(l != 0 || fy == yy); + } + while (fy >= 0) + { + FreeMline(mlf); + if (--fy >= 0) + mlf = OLDWIN(fy); + } + while (ty >= 0) + { + if (AllocMline(mlt, wi + 1)) + goto nomem; + MakeBlankLine(mlt->image, wi + 1); + if (--ty >= 0) + mlt = NEWWIN(ty); + } + +#ifdef DEBUG + if (nmlines != p->w_mlines) + for (fy = 0; fy < p->w_height + p->w_histheight; fy++) + { + ml = OLDWIN(fy); + ASSERT(ml->image == 0); + } +#endif + + if (p->w_mlines && p->w_mlines != nmlines) + free((char *)p->w_mlines); + p->w_mlines = nmlines; +#ifdef COPY_PASTE + if (p->w_hlines && p->w_hlines != nhlines) + free((char *)p->w_hlines); + p->w_hlines = nhlines; +#endif + nmlines = nhlines = 0; + + /* change tabs */ + if (p->w_width != wi) + { + if (wi) + { + if (p->w_tabs == 0) + { + /* tabs get wi+1 because 0 <= x <= wi */ + p->w_tabs = malloc((unsigned) wi + 1); + t = 8; + } + else + { + p->w_tabs = xrealloc(p->w_tabs, wi + 1); + t = p->w_width; + } + if (p->w_tabs == 0) + { + nomem: + if (nmlines) + { + for (ty = he + hi - 1; ty >= 0; ty--) + { + mlt = NEWWIN(ty); + FreeMline(mlt); + } + if (nmlines && p->w_mlines != nmlines) + free((char *)nmlines); +#ifdef COPY_PASTE + if (nhlines && p->w_hlines != nhlines) + free((char *)nhlines); +#endif + } + KillWindow(p); + Msg(0, strnomem); + return -1; + } + for (t = (t + 7) & 8; t < wi; t += 8) + p->w_tabs[t] = 1; + } + else + { + if (p->w_tabs) + free(p->w_tabs); + p->w_tabs = 0; + } + } + + /* Change w_Saved_y - this is only an estimate... */ + p->w_Saved_y += ncy - p->w_y; + + p->w_x = ncx; + p->w_y = ncy; + if (p->w_autoaka > 0) + p->w_autoaka = naka; + + /* do sanity checks */ + if (p->w_x > wi) + p->w_x = wi; + if (p->w_y >= he) + p->w_y = he - 1; + if (p->w_Saved_x > wi) + p->w_Saved_x = wi; + if (p->w_Saved_y < 0) + p->w_Saved_y = 0; + if (p->w_Saved_y >= he) + p->w_Saved_y = he - 1; + + /* reset scrolling region */ + p->w_top = 0; + p->w_bot = he - 1; + + /* signal new size to window */ +#ifdef TIOCSWINSZ + if (wi && (p->w_width != wi || p->w_height != he) && p->w_ptyfd >= 0 && p->w_pid) + { + glwz.ws_col = wi; + glwz.ws_row = he; + debug("Setting pty winsize.\n"); + if (ioctl(p->w_ptyfd, TIOCSWINSZ, (char *)&glwz)) + debug2("SetPtySize: errno %d (fd:%d)\n", errno, p->w_ptyfd); + } +#endif /* TIOCSWINSZ */ + + /* store new size */ + p->w_width = wi; + p->w_height = he; +#ifdef COPY_PASTE + p->w_histidx = 0; + p->w_histheight = hi; +#endif + +#ifdef DEBUG + /* Test if everything was ok */ + for (fy = 0; fy < p->w_height + p->w_histheight; fy++) + { + ml = OLDWIN(fy); + ASSERT(ml->image); + for (l = 0; l < p->w_width; l++) + ASSERT((unsigned char)ml->image[l] >= ' '); + } +#endif + return 0; +} + |