1/* Copyright (c) 1993-2002
2 *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
20 *
21 ****************************************************************
22 */
23
24#include <sys/types.h>
25#include <signal.h>
26#ifndef sun
27#include <sys/ioctl.h>
28#endif
29
30#ifdef ISC
31# include <sys/tty.h>
32# include <sys/sioctl.h>
33# include <sys/pty.h>
34#endif
35
36#include "config.h"
37#include "screen.h"
38#include "extern.h"
39
40static void CheckMaxSize __P((int));
41static void FreeMline  __P((struct mline *));
42static int  AllocMline __P((struct mline *ml, int));
43static void MakeBlankLine __P((unsigned char *, int));
44static void kaablamm __P((void));
45static int  BcopyMline __P((struct mline *, int, struct mline *, int, int, int));
46static void SwapAltScreen __P((struct win *));
47
48extern struct layer *flayer;
49extern struct display *display, *displays;
50extern unsigned char *blank, *null;
51extern struct mline mline_blank, mline_null, mline_old;
52extern struct win *windows;
53extern int Z0width, Z1width;
54extern int captionalways;
55
56#if defined(TIOCGWINSZ) || defined(TIOCSWINSZ)
57struct winsize glwz;
58#endif
59
60static struct mline mline_zero = {
61 (unsigned char *)0,
62 (unsigned char *)0
63#ifdef FONT
64 ,(unsigned char *)0
65#endif
66#ifdef COLOR
67 ,(unsigned char *)0
68# ifdef COLORS256
69 ,(unsigned char *)0
70# endif
71#endif
72};
73
74/*
75 * ChangeFlag:   0: try to modify no window
76 *               1: modify fore (and try to modify no other) + redisplay
77 *               2: modify all windows
78 *
79 * Note: Activate() is only called if change_flag == 1
80 *       i.e. on a WINCH event
81 */
82
83void
84CheckScreenSize(change_flag)
85int change_flag;
86{
87  int wi, he;
88
89  if (display == 0)
90    {
91      debug("CheckScreenSize: No display -> no check.\n");
92      return;
93    }
94#ifdef TIOCGWINSZ
95  if (ioctl(D_userfd, TIOCGWINSZ, (char *)&glwz) != 0)
96    {
97      debug2("CheckScreenSize: ioctl(%d, TIOCGWINSZ) errno %d\n", D_userfd, errno);
98      wi = D_CO;
99      he = D_LI;
100    }
101  else
102    {
103      wi = glwz.ws_col;
104      he = glwz.ws_row;
105      if (wi == 0)
106        wi = D_CO;
107      if (he == 0)
108        he = D_LI;
109    }
110#else
111  wi = D_CO;
112  he = D_LI;
113#endif
114
115  debug2("CheckScreenSize: screen is (%d,%d)\n", wi, he);
116
117#if 0 /* XXX: Fixme */
118  if (change_flag == 2)
119    {
120      debug("Trying to adapt all windows (-A)\n");
121      for (p = windows; p; p = p->w_next)
122	if (p->w_display == 0 || p->w_display == display)
123          ChangeWindowSize(p, wi, he, p->w_histheight);
124    }
125#endif
126  if (D_width == wi && D_height == he)
127    {
128      debug("CheckScreenSize: No change -> return.\n");
129      return;
130    }
131#ifdef BLANKER_PRG
132  KillBlanker();
133#endif
134  ResetIdle();
135  ChangeScreenSize(wi, he, change_flag);
136/* XXX Redisplay logic */
137#if 0
138  if (change_flag == 1)
139    Redisplay(D_fore ? D_fore->w_norefresh : 0);
140#endif
141}
142
143void
144ChangeScreenSize(wi, he, change_fore)
145int wi, he;
146int change_fore;
147{
148  struct win *p;
149  struct canvas *cv, **cvpp;
150  int wwi;
151  int y, h, hn;
152
153  debug2("ChangeScreenSize from (%d,%d) ", D_width, D_height);
154  debug3("to (%d,%d) (change_fore: %d)\n",wi, he, change_fore);
155
156  /*
157   *  STRATEGY: keep the ratios.
158   *  if canvas doesn't fit anymore, throw it off.
159   *  (ATTENTION: cvlist must be sorted!)
160   */
161  y = 0;
162  h = he;
163  if (D_has_hstatus == HSTATUS_LASTLINE)
164    {
165      if (h > 1)
166        h--;
167      else
168        D_has_hstatus = 0;	/* sorry */
169    }
170  for (cvpp = &D_cvlist; (cv = *cvpp); )
171    {
172      if (h < 2 && cvpp != &D_cvlist)
173        {
174          /* kill canvas */
175	  SetCanvasWindow(cv, 0);
176          *cvpp = cv->c_next;
177	  free(cv);
178	  if (D_forecv == cv)
179	    D_forecv = 0;
180          continue;
181        }
182      hn = (cv->c_ye - cv->c_ys + 1) * he / D_height;
183      if (hn == 0)
184        hn = 1;
185      if (hn + 2 >= h || cv->c_next == 0)
186        hn = h - 1;
187      if ((!captionalways && cv == D_cvlist && h - hn < 2) || hn == 0)
188        hn = h;
189      ASSERT(hn > 0);
190      cv->c_xs = 0;
191      cv->c_xe = wi - 1;
192      cv->c_ys = y;
193      cv->c_ye = y + hn - 1;
194
195      cv->c_xoff = cv->c_xs;
196      cv->c_yoff = cv->c_ys;
197
198      y += hn + 1;
199      h -= hn + 1;
200      cvpp = &cv->c_next;
201    }
202  RethinkDisplayViewports();
203  if (D_forecv == 0)
204    D_forecv = D_cvlist;
205  if (D_forecv)
206    D_fore = Layer2Window(D_forecv->c_layer);
207
208  D_width = wi;
209  D_height = he;
210
211  CheckMaxSize(wi);
212  if (D_CWS)
213    {
214      D_defwidth = D_CO;
215      D_defheight = D_LI;
216    }
217  else
218    {
219      if (D_CZ0 && (wi == Z0width || wi == Z1width) &&
220          (D_CO == Z0width || D_CO == Z1width))
221        D_defwidth = D_CO;
222      else
223        D_defwidth = wi;
224      D_defheight = he;
225    }
226  debug2("Default size: (%d,%d)\n", D_defwidth, D_defheight);
227  if (change_fore)
228    ResizeLayersToCanvases();
229  if (D_CWS == NULL && displays->d_next == 0)
230    {
231      /* adapt all windows  -  to be removed ? */
232      for (p = windows; p; p = p->w_next)
233        {
234          debug1("Trying to change window %d.\n", p->w_number);
235          wwi = wi;
236#if 0
237          if (D_CZ0 && p->w_width != wi && (wi == Z0width || wi == Z1width))
238	    {
239	      if (p->w_width > (Z0width + Z1width) / 2)
240		wwi = Z0width;
241	      else
242		wwi = Z1width;
243	    }
244#endif
245	  if (p->w_savelayer && p->w_savelayer->l_cvlist == 0)
246	    ResizeLayer(p->w_savelayer, wwi, he, 0);
247#if 0
248          ChangeWindowSize(p, wwi, he, p->w_histheight);
249#endif
250        }
251    }
252}
253
254void
255ResizeLayersToCanvases()
256{
257  struct canvas *cv;
258  struct layer *l;
259  int lx, ly;
260
261  debug("ResizeLayersToCanvases\n");
262  D_kaablamm = 0;
263  for (cv = D_cvlist; cv; cv = cv->c_next)
264    {
265      l = cv->c_layer;
266      if (l == 0)
267	continue;
268      debug("Doing canvas: ");
269      if (l->l_width  == cv->c_xe - cv->c_xs + 1 &&
270          l->l_height == cv->c_ye - cv->c_ys + 1)
271        {
272          debug("already fitting.\n");
273          continue;
274        }
275      if (!MayResizeLayer(l))
276        {
277          debug("may not resize.\n");
278        }
279      else
280	{
281	  debug("doing resize.\n");
282	  ResizeLayer(l, cv->c_xe - cv->c_xs + 1, cv->c_ye - cv->c_ys + 1, display);
283	}
284
285      /* normalize window, see screen.c */
286      lx = cv->c_layer->l_x;
287      ly = cv->c_layer->l_y;
288      if (ly + cv->c_yoff < cv->c_ys)
289	{
290          cv->c_yoff = cv->c_ys - ly;
291          RethinkViewportOffsets(cv);
292	}
293      else if (ly + cv->c_yoff > cv->c_ye)
294	{
295	  cv->c_yoff = cv->c_ye - ly;
296          RethinkViewportOffsets(cv);
297	}
298      if (lx + cv->c_xoff < cv->c_xs)
299        {
300	  int n = cv->c_xs - (lx + cv->c_xoff);
301	  if (n < (cv->c_xe - cv->c_xs + 1) / 2)
302	    n = (cv->c_xe - cv->c_xs + 1) / 2;
303	  if (cv->c_xoff + n > cv->c_xs)
304	    n = cv->c_xs - cv->c_xoff;
305	  cv->c_xoff += n;
306	  RethinkViewportOffsets(cv);
307        }
308      else if (lx + cv->c_xoff > cv->c_xe)
309	{
310	  int n = lx + cv->c_xoff - cv->c_xe;
311	  if (n < (cv->c_xe - cv->c_xs + 1) / 2)
312	    n = (cv->c_xe - cv->c_xs + 1) / 2;
313	  if (cv->c_xoff - n + cv->c_layer->l_width - 1 < cv->c_xe)
314	    n = cv->c_xoff + cv->c_layer->l_width - 1 - cv->c_xe;
315	  cv->c_xoff -= n;
316	  RethinkViewportOffsets(cv);
317	}
318    }
319  Redisplay(0);
320  if (D_kaablamm)
321    {
322      kaablamm();
323      D_kaablamm = 0;
324    }
325}
326
327int
328MayResizeLayer(l)
329struct layer *l;
330{
331  int cvs = 0;
332  debug("MayResizeLayer:\n");
333  for (; l; l = l->l_next)
334    {
335      if (l->l_cvlist)
336        if (++cvs > 1 || l->l_cvlist->c_lnext)
337	  {
338	    debug1("may not - cvs %d\n", cvs);
339	    return 0;
340	  }
341    }
342  debug("may resize\n");
343  return 1;
344}
345
346/*
347 *  Easy implementation: rely on the fact that the only layers
348 *  supporting resize are Win and Blank. So just kill all overlays.
349 *
350 *  This is a lot harder if done the right way...
351 */
352
353static void
354kaablamm()
355{
356  Msg(0, "Aborted because of window size change.");
357}
358
359void
360ResizeLayer(l, wi, he, norefdisp)
361struct layer *l;
362int wi, he;
363struct display *norefdisp;
364{
365  struct win *p;
366  struct canvas *cv;
367  struct layer *oldflayer = flayer;
368  struct display *d, *olddisplay = display;
369
370  if (l->l_width == wi && l->l_height == he)
371    return;
372  p = Layer2Window(l);
373
374  if (oldflayer && (l == oldflayer || Layer2Window(oldflayer) == p))
375    while (oldflayer->l_next)
376      oldflayer = oldflayer->l_next;
377
378  if (p)
379    {
380      for (d = displays; d; d = d->d_next)
381	for (cv = d->d_cvlist; cv; cv = cv->c_next)
382	  {
383	    if (p == Layer2Window(cv->c_layer))
384	      {
385		flayer = cv->c_layer;
386		if (flayer->l_next)
387		  d->d_kaablamm = 1;
388	        while (flayer->l_next)
389		  ExitOverlayPage();
390	      }
391	  }
392      l = p->w_savelayer;
393    }
394  flayer = l;
395  if (p == 0 && flayer->l_next && flayer->l_next->l_next == 0 && LayResize(wi, he) == 0)
396    {
397      flayer = flayer->l_next;
398      LayResize(wi, he);
399      flayer = l;
400    }
401  else
402    {
403      if (flayer->l_next)
404        for (cv = flayer->l_cvlist; cv; cv = cv->c_lnext)
405	  cv->c_display->d_kaablamm = 1;
406      while (flayer->l_next)
407	ExitOverlayPage();
408    }
409  if (p)
410    flayer = &p->w_layer;
411  LayResize(wi, he);
412  /* now everybody is on flayer, redisplay */
413  l = flayer;
414  for (display = displays; display; display = display->d_next)
415    {
416      if (display == norefdisp)
417	continue;
418      for (cv = D_cvlist; cv; cv = cv->c_next)
419	if (cv->c_layer == l)
420	  {
421            CV_CALL(cv, LayRedisplayLine(-1, -1, -1, 0));
422            RefreshArea(cv->c_xs, cv->c_ys, cv->c_xe, cv->c_ye, 0);
423	  }
424      if (D_kaablamm)
425	{
426	  kaablamm();
427	  D_kaablamm = 0;
428	}
429    }
430  flayer = oldflayer;
431  display = olddisplay;
432}
433
434
435static void
436FreeMline(ml)
437struct mline *ml;
438{
439  if (ml->image)
440    free(ml->image);
441  if (ml->attr && ml->attr != null)
442    free(ml->attr);
443#ifdef FONT
444  if (ml->font && ml->font != null)
445    free(ml->font);
446#endif
447#ifdef COLOR
448  if (ml->color && ml->color != null)
449    free(ml->color);
450# ifdef COLORS256
451  if (ml->colorx && ml->colorx != null)
452    free(ml->colorx);
453# endif
454#endif
455  *ml = mline_zero;
456}
457
458static int
459AllocMline(ml, w)
460struct mline *ml;
461int w;
462{
463  ml->image = malloc(w);
464  ml->attr  = null;
465#ifdef FONT
466  ml->font  = null;
467#endif
468#ifdef COLOR
469  ml->color = null;
470# ifdef COLORS256
471  ml->colorx = null;
472# endif
473#endif
474  if (ml->image == 0)
475    return -1;
476  return 0;
477}
478
479
480static int
481BcopyMline(mlf, xf, mlt, xt, l, w)
482struct mline *mlf, *mlt;
483int xf, xt, l, w;
484{
485  int r = 0;
486
487  bcopy((char *)mlf->image + xf, (char *)mlt->image + xt, l);
488  if (mlf->attr != null && mlt->attr == null)
489    {
490      if ((mlt->attr = (unsigned char *)malloc(w)) == 0)
491	mlt->attr = null, r = -1;
492      bzero((char *)mlt->attr, w);
493    }
494  if (mlt->attr != null)
495    bcopy((char *)mlf->attr + xf, (char *)mlt->attr + xt, l);
496#ifdef FONT
497  if (mlf->font != null && mlt->font == null)
498    {
499      if ((mlt->font = (unsigned char *)malloc(w)) == 0)
500	mlt->font = null, r = -1;
501      bzero((char *)mlt->font, w);
502    }
503  if (mlt->font != null)
504    bcopy((char *)mlf->font + xf, (char *)mlt->font + xt, l);
505#endif
506#ifdef COLOR
507  if (mlf->color != null && mlt->color == null)
508    {
509      if ((mlt->color = (unsigned char *)malloc(w)) == 0)
510	mlt->color = null, r = -1;
511      bzero((char *)mlt->color, w);
512    }
513  if (mlt->color != null)
514    bcopy((char *)mlf->color + xf, (char *)mlt->color + xt, l);
515# ifdef COLORS256
516  if (mlf->colorx != null && mlt->colorx == null)
517    {
518      if ((mlt->colorx = (unsigned char *)malloc(w)) == 0)
519	mlt->colorx = null, r = -1;
520      bzero((char *)mlt->colorx, w);
521    }
522  if (mlt->colorx != null)
523    bcopy((char *)mlf->colorx + xf, (char *)mlt->colorx + xt, l);
524# endif
525#endif
526  return r;
527}
528
529
530static int maxwidth;
531
532static void
533CheckMaxSize(wi)
534int wi;
535{
536  unsigned char *oldnull = null;
537  struct win *p;
538  int i;
539  struct mline *ml;
540
541  wi = ((wi + 1) + 255) & ~255;
542  if (wi <= maxwidth)
543    return;
544  maxwidth = wi;
545  debug1("New maxwidth: %d\n", maxwidth);
546  blank = (unsigned char *)xrealloc((char *)blank, maxwidth);
547  null = (unsigned char *)xrealloc((char *)null, maxwidth);
548  mline_old.image = (unsigned char *)xrealloc((char *)mline_old.image, maxwidth);
549  mline_old.attr = (unsigned char *)xrealloc((char *)mline_old.attr, maxwidth);
550#ifdef FONT
551  mline_old.font = (unsigned char *)xrealloc((char *)mline_old.font, maxwidth);
552#endif
553#ifdef COLOR
554  mline_old.color = (unsigned char *)xrealloc((char *)mline_old.color, maxwidth);
555# ifdef COLORS256
556  mline_old.colorx = (unsigned char *)xrealloc((char *)mline_old.color, maxwidth);
557# endif
558#endif
559  if (!(blank && null && mline_old.image && mline_old.attr IFFONT(&& mline_old.font) IFCOLOR(&& mline_old.color) IFCOLORX(&& mline_old.colorx)))
560    Panic(0, strnomem);
561
562  MakeBlankLine(blank, maxwidth);
563  bzero((char *)null, maxwidth);
564
565  mline_blank.image = blank;
566  mline_blank.attr  = null;
567  mline_null.image = null;
568  mline_null.attr  = null;
569#ifdef FONT
570  mline_blank.font  = null;
571  mline_null.font  = null;
572#endif
573#ifdef COLOR
574  mline_blank.color = null;
575  mline_null.color = null;
576# ifdef COLORS256
577  mline_blank.colorx = null;
578  mline_null.colorx = null;
579# endif
580#endif
581
582  /* We have to run through all windows to substitute
583   * the null references.
584   */
585  for (p = windows; p; p = p->w_next)
586    {
587      ml = p->w_mlines;
588      for (i = 0; i < p->w_height; i++, ml++)
589	{
590	  if (ml->attr == oldnull)
591	    ml->attr = null;
592#ifdef FONT
593	  if (ml->font == oldnull)
594	    ml->font = null;
595#endif
596#ifdef COLOR
597	  if (ml->color == oldnull)
598	    ml->color= null;
599#ifdef COLORS256
600	  if (ml->colorx == oldnull)
601	    ml->colorx = null;
602#endif
603#endif
604	}
605#ifdef COPY_PASTE
606      ml = p->w_hlines;
607      for (i = 0; i < p->w_histheight; i++, ml++)
608	{
609	  if (ml->attr == oldnull)
610	    ml->attr = null;
611# ifdef FONT
612	  if (ml->font == oldnull)
613	    ml->font = null;
614# endif
615# ifdef COLOR
616	  if (ml->color == oldnull)
617	    ml->color= null;
618#  ifdef COLORS256
619	  if (ml->colorx == oldnull)
620	    ml->colorx = null;
621#  endif
622# endif
623	}
624#endif
625    }
626}
627
628
629char *
630xrealloc(mem, len)
631char *mem;
632int len;
633{
634  register char *nmem;
635
636  if (mem == 0)
637    return malloc(len);
638  if ((nmem = realloc(mem, len)))
639    return nmem;
640  free(mem);
641  return (char *)0;
642}
643
644static void
645MakeBlankLine(p, n)
646register unsigned char *p;
647register int n;
648{
649  while (n--)
650    *p++ = ' ';
651}
652
653
654
655
656#ifdef COPY_PASTE
657
658#define OLDWIN(y) ((y < p->w_histheight) \
659        ? &p->w_hlines[(p->w_histidx + y) % p->w_histheight] \
660        : &p->w_mlines[y - p->w_histheight])
661
662#define NEWWIN(y) ((y < hi) ? &nhlines[y] : &nmlines[y - hi])
663
664#else
665
666#define OLDWIN(y) (&p->w_mlines[y])
667#define NEWWIN(y) (&nmlines[y])
668
669#endif
670
671
672int
673ChangeWindowSize(p, wi, he, hi)
674struct win *p;
675int wi, he, hi;
676{
677  struct mline *mlf = 0, *mlt = 0, *ml, *nmlines, *nhlines;
678  int fy, ty, l, lx, lf, lt, yy, oty, addone;
679  int ncx, ncy, naka, t;
680  int y, shift;
681
682  if (wi == 0)
683    he = hi = 0;
684
685  if (p->w_width == wi && p->w_height == he && p->w_histheight == hi)
686    {
687      debug("ChangeWindowSize: No change.\n");
688      return 0;
689    }
690
691  CheckMaxSize(wi);
692
693  /* XXX */
694#if 0
695  /* just in case ... */
696  if (wi && (p->w_width != wi || p->w_height != he) && p->w_lay != &p->w_winlay)
697    {
698      debug("ChangeWindowSize: No resize because of overlay?\n");
699      return -1;
700    }
701#endif
702
703  debug("ChangeWindowSize");
704  debug3(" from (%d,%d)+%d", p->w_width, p->w_height, p->w_histheight);
705  debug3(" to(%d,%d)+%d\n", wi, he, hi);
706
707  fy = p->w_histheight + p->w_height - 1;
708  ty = hi + he - 1;
709
710  nmlines = nhlines = 0;
711  ncx = 0;
712  ncy = 0;
713  naka = 0;
714
715  if (wi)
716    {
717      if (wi != p->w_width || he != p->w_height)
718	{
719	  if ((nmlines = (struct mline *)calloc(he, sizeof(struct mline))) == 0)
720	    {
721	      KillWindow(p);
722	      Msg(0, strnomem);
723	      return -1;
724	    }
725	}
726      else
727	{
728	  debug1("image stays the same: %d lines\n", he);
729	  nmlines = p->w_mlines;
730	  fy -= he;
731	  ty -= he;
732	  ncx = p->w_x;
733	  ncy = p->w_y;
734	  naka = p->w_autoaka;
735	}
736    }
737#ifdef COPY_PASTE
738  if (hi)
739    {
740      if ((nhlines = (struct mline *)calloc(hi, sizeof(struct mline))) == 0)
741	{
742	  Msg(0, "No memory for history buffer - turned off");
743	  hi = 0;
744	  ty = he - 1;
745	}
746    }
747#endif
748
749  /* special case: cursor is at magic margin position */
750  addone = 0;
751  if (p->w_width && p->w_x == p->w_width)
752    {
753      debug2("Special addone case: %d %d\n", p->w_x, p->w_y);
754      addone = 1;
755      p->w_x--;
756    }
757
758  /* handle the cursor and autoaka lines now if the widths are equal */
759  if (p->w_width == wi)
760    {
761      ncx = p->w_x + addone;
762      ncy = p->w_y + he - p->w_height;
763      /* never lose sight of the line with the cursor on it */
764      shift = -ncy;
765      for (yy = p->w_y + p->w_histheight - 1; yy >= 0 && ncy + shift < he; yy--)
766	{
767	  ml = OLDWIN(yy);
768	  if (ml->image[p->w_width] == ' ')
769	    break;
770	  shift++;
771	}
772      if (shift < 0)
773	shift = 0;
774      else
775	debug1("resize: cursor out of bounds, shifting %d\n", shift);
776      ncy += shift;
777      if (p->w_autoaka > 0)
778	{
779	  naka = p->w_autoaka + he - p->w_height + shift;
780	  if (naka < 1 || naka > he)
781	    naka = 0;
782	}
783      while (shift-- > 0)
784	{
785	  ml = OLDWIN(fy);
786	  FreeMline(ml);
787	  fy--;
788	}
789    }
790  debug2("fy %d ty %d\n", fy, ty);
791  if (fy >= 0)
792    mlf = OLDWIN(fy);
793  if (ty >= 0)
794    mlt = NEWWIN(ty);
795
796  while (fy >= 0 && ty >= 0)
797    {
798      if (p->w_width == wi)
799	{
800	  /* here is a simple shortcut: just copy over */
801	  *mlt = *mlf;
802          *mlf = mline_zero;
803	  if (--fy >= 0)
804	    mlf = OLDWIN(fy);
805	  if (--ty >= 0)
806	    mlt = NEWWIN(ty);
807	  continue;
808	}
809
810      /* calculate lenght */
811      for (l = p->w_width - 1; l > 0; l--)
812	if (mlf->image[l] != ' ' || mlf->attr[l])
813	  break;
814      if (fy == p->w_y + p->w_histheight && l < p->w_x)
815	l = p->w_x;	/* cursor is non blank */
816      l++;
817      lf = l;
818
819      /* add wrapped lines to length */
820      for (yy = fy - 1; yy >= 0; yy--)
821	{
822	  ml = OLDWIN(yy);
823	  if (ml->image[p->w_width] == ' ')
824	    break;
825	  l += p->w_width;
826	}
827
828      /* rewrap lines */
829      lt = (l - 1) % wi + 1;	/* lf is set above */
830      oty = ty;
831      while (l > 0 && fy >= 0 && ty >= 0)
832	{
833	  lx = lt > lf ? lf : lt;
834	  if (mlt->image == 0)
835	    {
836	      if (AllocMline(mlt, wi + 1))
837		goto nomem;
838    	      MakeBlankLine(mlt->image + lt, wi - lt);
839	      mlt->image[wi] = ((oty == ty) ? ' ' : 0);
840	    }
841	  if (BcopyMline(mlf, lf - lx, mlt, lt - lx, lx, wi + 1))
842	    goto nomem;
843
844	  /* did we copy the cursor ? */
845	  if (fy == p->w_y + p->w_histheight && lf - lx <= p->w_x && lf > p->w_x)
846	    {
847	      ncx = p->w_x + lt - lf + addone;
848	      ncy = ty - hi;
849	      shift = wi ? -ncy + (l - lx) / wi : 0;
850	      if (ty + shift > hi + he - 1)
851		shift = hi + he - 1 - ty;
852	      if (shift > 0)
853		{
854	          debug3("resize: cursor out of bounds, shifting %d [%d/%d]\n", shift, lt - lx, wi);
855		  for (y = hi + he - 1; y >= ty; y--)
856		    {
857		      mlt = NEWWIN(y);
858		      FreeMline(mlt);
859		      if (y - shift < ty)
860			continue;
861		      ml  = NEWWIN(y - shift);
862		      *mlt = *ml;
863		      *ml = mline_zero;
864		    }
865		  ncy += shift;
866		  ty += shift;
867		  mlt = NEWWIN(ty);
868		  if (naka > 0)
869		    naka = naka + shift > he ? 0 : naka + shift;
870		}
871	      ASSERT(ncy >= 0);
872	    }
873	  /* did we copy autoaka line ? */
874	  if (p->w_autoaka > 0 && fy == p->w_autoaka - 1 + p->w_histheight && lf - lx <= 0)
875	    naka = ty - hi >= 0 ? 1 + ty - hi : 0;
876
877	  lf -= lx;
878	  lt -= lx;
879	  l  -= lx;
880	  if (lf == 0)
881	    {
882	      FreeMline(mlf);
883	      lf = p->w_width;
884	      if (--fy >= 0)
885	        mlf = OLDWIN(fy);
886	    }
887	  if (lt == 0)
888	    {
889	      lt = wi;
890	      if (--ty >= 0)
891	        mlt = NEWWIN(ty);
892	    }
893	}
894      ASSERT(l != 0 || fy == yy);
895    }
896  while (fy >= 0)
897    {
898      FreeMline(mlf);
899      if (--fy >= 0)
900	mlf = OLDWIN(fy);
901    }
902  while (ty >= 0)
903    {
904      if (AllocMline(mlt, wi + 1))
905	goto nomem;
906      MakeBlankLine(mlt->image, wi + 1);
907      if (--ty >= 0)
908	mlt = NEWWIN(ty);
909    }
910
911#ifdef DEBUG
912  if (nmlines != p->w_mlines)
913    for (fy = 0; fy < p->w_height + p->w_histheight; fy++)
914      {
915	ml = OLDWIN(fy);
916	ASSERT(ml->image == 0);
917      }
918#endif
919
920  if (p->w_mlines && p->w_mlines != nmlines)
921    free((char *)p->w_mlines);
922  p->w_mlines = nmlines;
923#ifdef COPY_PASTE
924  if (p->w_hlines && p->w_hlines != nhlines)
925    free((char *)p->w_hlines);
926  p->w_hlines = nhlines;
927#endif
928  nmlines = nhlines = 0;
929
930  /* change tabs */
931  if (p->w_width != wi)
932    {
933      if (wi)
934	{
935	  t = p->w_tabs ? p->w_width : 0;
936	  p->w_tabs = xrealloc(p->w_tabs, wi + 1);
937	  if (p->w_tabs == 0)
938	    {
939	    nomem:
940	      if (nmlines)
941		{
942		  for (ty = he + hi - 1; ty >= 0; ty--)
943		    {
944		      mlt = NEWWIN(ty);
945		      FreeMline(mlt);
946		    }
947		  if (nmlines && p->w_mlines != nmlines)
948		    free((char *)nmlines);
949#ifdef COPY_PASTE
950		  if (nhlines && p->w_hlines != nhlines)
951		    free((char *)nhlines);
952#endif
953		}
954	      KillWindow(p);
955	      Msg(0, strnomem);
956	      return -1;
957	    }
958	  for (; t < wi; t++)
959	    p->w_tabs[t] = t && !(t & 7) ? 1 : 0;
960	  p->w_tabs[wi] = 0;
961	}
962      else
963	{
964	  if (p->w_tabs)
965	    free(p->w_tabs);
966	  p->w_tabs = 0;
967	}
968    }
969
970  /* Change w_Saved_y - this is only an estimate... */
971  p->w_Saved_y += ncy - p->w_y;
972
973  p->w_x = ncx;
974  p->w_y = ncy;
975  if (p->w_autoaka > 0)
976    p->w_autoaka = naka;
977
978  /* do sanity checks */
979  if (p->w_x > wi)
980    p->w_x = wi;
981  if (p->w_y >= he)
982    p->w_y = he - 1;
983  if (p->w_Saved_x > wi)
984    p->w_Saved_x = wi;
985  if (p->w_Saved_y < 0)
986    p->w_Saved_y = 0;
987  if (p->w_Saved_y >= he)
988    p->w_Saved_y = he - 1;
989
990  /* reset scrolling region */
991  p->w_top = 0;
992  p->w_bot = he - 1;
993
994  /* signal new size to window */
995#ifdef TIOCSWINSZ
996  if (wi && (p->w_width != wi || p->w_height != he) && p->w_ptyfd >= 0 && p->w_pid)
997    {
998      glwz.ws_col = wi;
999      glwz.ws_row = he;
1000      debug("Setting pty winsize.\n");
1001      if (ioctl(p->w_ptyfd, TIOCSWINSZ, (char *)&glwz))
1002	debug2("SetPtySize: errno %d (fd:%d)\n", errno, p->w_ptyfd);
1003    }
1004#endif /* TIOCSWINSZ */
1005
1006  /* store new size */
1007  p->w_width = wi;
1008  p->w_height = he;
1009#ifdef COPY_PASTE
1010  p->w_histidx = 0;
1011  p->w_histheight = hi;
1012#endif
1013
1014#ifdef BUILTIN_TELNET
1015  if (p->w_type == W_TYPE_TELNET)
1016    TelWindowSize(p);
1017#endif
1018
1019#ifdef DEBUG
1020  /* Test if everything was ok */
1021  for (fy = 0; fy < p->w_height + p->w_histheight; fy++)
1022    {
1023      ml = OLDWIN(fy);
1024      ASSERT(ml->image);
1025# ifdef UTF8
1026      if (p->w_encoding == UTF8)
1027	{
1028	  for (l = 0; l < p->w_width; l++)
1029	    ASSERT(ml->image[l] >= ' ' || ml->font[l]);
1030	}
1031      else
1032#endif
1033        for (l = 0; l < p->w_width; l++)
1034          ASSERT(ml->image[l] >= ' ');
1035    }
1036#endif
1037  return 0;
1038}
1039
1040void
1041FreeAltScreen(p)
1042struct win *p;
1043{
1044  int i;
1045
1046  if (p->w_alt_mlines)
1047    for (i = 0; i < p->w_alt_height; i++)
1048      FreeMline(p->w_alt_mlines + i);
1049  p->w_alt_mlines = 0;
1050  p->w_alt_width = 0;
1051  p->w_alt_height = 0;
1052  p->w_alt_x = 0;
1053  p->w_alt_y = 0;
1054#ifdef COPY_PASTE
1055  if (p->w_alt_hlines)
1056    for (i = 0; i < p->w_alt_histheight; i++)
1057      FreeMline(p->w_alt_hlines + i);
1058  p->w_alt_hlines = 0;
1059  p->w_alt_histidx = 0;
1060#endif
1061  p->w_alt_histheight = 0;
1062}
1063
1064static void
1065SwapAltScreen(p)
1066struct win *p;
1067{
1068  struct mline *ml;
1069  int t;
1070
1071  ml = p->w_alt_mlines; p->w_alt_mlines = p->w_mlines; p->w_mlines = ml;
1072  t = p->w_alt_width; p->w_alt_width = p->w_width; p->w_width = t;
1073  t = p->w_alt_height; p->w_alt_height = p->w_height; p->w_height = t;
1074  t = p->w_alt_histheight; p->w_alt_histheight = p->w_histheight; p->w_histheight = t;
1075  t = p->w_alt_x; p->w_alt_x = p->w_x; p->w_x = t;
1076  t = p->w_alt_y; p->w_alt_y = p->w_y; p->w_y = t;
1077#ifdef COPY_PASTE
1078  ml = p->w_alt_hlines; p->w_alt_hlines = p->w_hlines; p->w_hlines = ml;
1079  t = p->w_alt_histidx; p->w_alt_histidx = p->w_histidx; p->w_histidx = t;
1080#endif
1081}
1082
1083void
1084EnterAltScreen(p)
1085struct win *p;
1086{
1087  int ox = p->w_x, oy = p->w_y;
1088  FreeAltScreen(p);
1089  SwapAltScreen(p);
1090  ChangeWindowSize(p, p->w_alt_width, p->w_alt_height, p->w_alt_histheight);
1091  p->w_x = ox;
1092  p->w_y = oy;
1093}
1094
1095void
1096LeaveAltScreen(p)
1097struct win *p;
1098{
1099  if (!p->w_alt_mlines)
1100    return;
1101  SwapAltScreen(p);
1102  ChangeWindowSize(p, p->w_alt_width, p->w_alt_height, p->w_alt_histheight);
1103  FreeAltScreen(p);
1104}
1105