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