Fix a bug with displaying blank spaces with bce on.
[screen-lua.git] / src / resize.c
blob61e044ff72fe308e1da44c0d2ebde860412384d0
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
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.
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.
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 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include <sys/types.h>
30 #include <signal.h>
31 #ifndef sun
32 #include <sys/ioctl.h>
33 #endif
35 #ifdef ISC
36 # include <sys/tty.h>
37 # include <sys/sioctl.h>
38 # include <sys/pty.h>
39 #endif
41 #include "config.h"
42 #include "screen.h"
43 #include "extern.h"
45 static void CheckMaxSize __P((int));
46 static void FreeMline __P((struct mline *));
47 static int AllocMline __P((struct mline *ml, int));
48 static void MakeBlankLine __P((unsigned char *, int));
49 static void kaablamm __P((void));
50 static int BcopyMline __P((struct mline *, int, struct mline *, int, int, int));
51 static void SwapAltScreen __P((struct win *));
53 extern struct layer *flayer;
54 extern struct display *display, *displays;
55 extern unsigned char *blank, *null;
56 extern struct mline mline_blank, mline_null, mline_old;
57 extern struct win *windows;
58 extern int Z0width, Z1width;
59 extern int captionalways;
61 #if defined(TIOCGWINSZ) || defined(TIOCSWINSZ)
62 struct winsize glwz;
63 #endif
65 static struct mline mline_zero = {
66 (unsigned char *)0,
67 (unsigned char *)0
68 #ifdef FONT
69 ,(unsigned char *)0
70 #endif
71 #ifdef COLOR
72 ,(unsigned char *)0
73 # ifdef COLORS256
74 ,(unsigned char *)0
75 # endif
76 #endif
80 * ChangeFlag: 0: try to modify no window
81 * 1: modify fore (and try to modify no other) + redisplay
82 * 2: modify all windows
84 * Note: Activate() is only called if change_flag == 1
85 * i.e. on a WINCH event
88 void
89 CheckScreenSize(change_flag)
90 int change_flag;
92 int wi, he;
94 if (display == 0)
96 debug("CheckScreenSize: No display -> no check.\n");
97 return;
99 #ifdef TIOCGWINSZ
100 if (ioctl(D_userfd, TIOCGWINSZ, (char *)&glwz) != 0)
102 debug2("CheckScreenSize: ioctl(%d, TIOCGWINSZ) errno %d\n", D_userfd, errno);
103 wi = D_CO;
104 he = D_LI;
106 else
108 wi = glwz.ws_col;
109 he = glwz.ws_row;
110 if (wi == 0)
111 wi = D_CO;
112 if (he == 0)
113 he = D_LI;
115 #else
116 wi = D_CO;
117 he = D_LI;
118 #endif
120 debug2("CheckScreenSize: screen is (%d,%d)\n", wi, he);
122 #if 0 /* XXX: Fixme */
123 if (change_flag == 2)
125 debug("Trying to adapt all windows (-A)\n");
126 for (p = windows; p; p = p->w_next)
127 if (p->w_display == 0 || p->w_display == display)
128 ChangeWindowSize(p, wi, he, p->w_histheight);
130 #endif
131 if (D_width == wi && D_height == he)
133 debug("CheckScreenSize: No change -> return.\n");
134 return;
136 #ifdef BLANKER_PRG
137 KillBlanker();
138 #endif
139 ResetIdle();
140 ChangeScreenSize(wi, he, change_flag);
141 /* XXX Redisplay logic */
142 #if 0
143 if (change_flag == 1)
144 Redisplay(D_fore ? D_fore->w_norefresh : 0);
145 #endif
148 void
149 ChangeScreenSize(wi, he, change_fore)
150 int wi, he;
151 int change_fore;
153 struct win *p;
154 struct canvas *cv;
155 int wwi;
157 debug2("ChangeScreenSize from (%d,%d) ", D_width, D_height);
158 debug3("to (%d,%d) (change_fore: %d)\n",wi, he, change_fore);
160 cv = &D_canvas;
161 cv->c_xe = wi - 1;
162 cv->c_ye = he - 1 - ((cv->c_slperp && cv->c_slperp->c_slnext) || captionalways) - (D_has_hstatus == HSTATUS_LASTLINE);
163 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
164 if (cv->c_slperp)
166 ResizeCanvas(cv);
167 RecreateCanvasChain();
168 RethinkDisplayViewports();
170 if (D_forecv == 0)
171 D_forecv = D_cvlist;
172 if (D_forecv)
173 D_fore = Layer2Window(D_forecv->c_layer);
175 D_width = wi;
176 D_height = he;
178 CheckMaxSize(wi);
179 if (D_CWS)
181 D_defwidth = D_CO;
182 D_defheight = D_LI;
184 else
186 if (D_CZ0 && (wi == Z0width || wi == Z1width) &&
187 (D_CO == Z0width || D_CO == Z1width))
188 D_defwidth = D_CO;
189 else
190 D_defwidth = wi;
191 D_defheight = he;
193 debug2("Default size: (%d,%d)\n", D_defwidth, D_defheight);
194 if (change_fore)
195 ResizeLayersToCanvases();
196 if (change_fore == 2 && D_CWS == NULL && displays->d_next == 0)
198 /* adapt all windows - to be removed ? */
199 for (p = windows; p; p = p->w_next)
201 debug1("Trying to change window %d.\n", p->w_number);
202 wwi = wi;
203 #if 0
204 if (D_CZ0 && p->w_width != wi && (wi == Z0width || wi == Z1width))
206 if (p->w_width > (Z0width + Z1width) / 2)
207 wwi = Z0width;
208 else
209 wwi = Z1width;
211 #endif
212 if (p->w_savelayer && p->w_savelayer->l_cvlist == 0)
213 ResizeLayer(p->w_savelayer, wwi, he, 0);
214 #if 0
215 ChangeWindowSize(p, wwi, he, p->w_histheight);
216 #endif
221 void
222 ResizeLayersToCanvases()
224 struct canvas *cv;
225 struct layer *l;
226 int lx, ly;
228 debug("ResizeLayersToCanvases\n");
229 D_kaablamm = 0;
230 for (cv = D_cvlist; cv; cv = cv->c_next)
232 l = cv->c_layer;
233 if (l == 0)
234 continue;
235 debug("Doing canvas: ");
236 if (l->l_width == cv->c_xe - cv->c_xs + 1 &&
237 l->l_height == cv->c_ye - cv->c_ys + 1)
239 debug("already fitting.\n");
240 continue;
242 if (!MayResizeLayer(l))
244 debug("may not resize.\n");
246 else
248 debug("doing resize.\n");
249 ResizeLayer(l, cv->c_xe - cv->c_xs + 1, cv->c_ye - cv->c_ys + 1, display);
252 /* normalize window, see screen.c */
253 lx = cv->c_layer->l_x;
254 ly = cv->c_layer->l_y;
255 if (ly + cv->c_yoff < cv->c_ys)
257 cv->c_yoff = cv->c_ys - ly;
258 RethinkViewportOffsets(cv);
260 else if (ly + cv->c_yoff > cv->c_ye)
262 cv->c_yoff = cv->c_ye - ly;
263 RethinkViewportOffsets(cv);
265 if (lx + cv->c_xoff < cv->c_xs)
267 int n = cv->c_xs - (lx + cv->c_xoff);
268 if (n < (cv->c_xe - cv->c_xs + 1) / 2)
269 n = (cv->c_xe - cv->c_xs + 1) / 2;
270 if (cv->c_xoff + n > cv->c_xs)
271 n = cv->c_xs - cv->c_xoff;
272 cv->c_xoff += n;
273 RethinkViewportOffsets(cv);
275 else if (lx + cv->c_xoff > cv->c_xe)
277 int n = lx + cv->c_xoff - cv->c_xe;
278 if (n < (cv->c_xe - cv->c_xs + 1) / 2)
279 n = (cv->c_xe - cv->c_xs + 1) / 2;
280 if (cv->c_xoff - n + cv->c_layer->l_width - 1 < cv->c_xe)
281 n = cv->c_xoff + cv->c_layer->l_width - 1 - cv->c_xe;
282 cv->c_xoff -= n;
283 RethinkViewportOffsets(cv);
286 Redisplay(0);
287 if (D_kaablamm)
289 kaablamm();
290 D_kaablamm = 0;
295 MayResizeLayer(l)
296 struct layer *l;
298 int cvs = 0;
299 debug("MayResizeLayer:\n");
300 for (; l; l = l->l_next)
302 if (l->l_cvlist)
303 if (++cvs > 1 || l->l_cvlist->c_lnext)
305 debug1("may not - cvs %d\n", cvs);
306 return 0;
309 debug("may resize\n");
310 return 1;
314 * Easy implementation: rely on the fact that the only layers
315 * supporting resize are Win and Blank. So just kill all overlays.
317 * This is a lot harder if done the right way...
320 static void
321 kaablamm()
323 Msg(0, "Aborted because of window size change.");
326 /* Kills non-resizable layers. */
327 #define RESIZE_OR_KILL_LAYERS(l, wi, he) do \
329 struct layer *_last = NULL, *_iter; \
330 flayer = (l); \
331 while (flayer->l_next) \
333 if (LayResize(wi, he) == 0) \
335 _last = flayer; \
336 flayer = flayer->l_next; \
338 else \
340 struct canvas *_cv; \
341 for (_cv = flayer->l_cvlist; _cv; _cv = _cv->c_lnext) \
342 _cv->c_display->d_kaablamm = 1; \
343 ExitOverlayPage(); \
344 if (_last) \
345 _last->l_next = flayer; \
348 /* We assume that the bottom-most layer, i.e. when flayer->l_next == 0, \
349 * is always resizable. Currently, WinLf and BlankLf can be the bottom-most layers. \
350 */ \
351 LayResize(wi, he); \
352 } while (0)
354 void
355 ResizeLayer(l, wi, he, norefdisp)
356 struct layer *l;
357 int wi, he;
358 struct display *norefdisp;
360 struct win *p;
361 struct canvas *cv;
362 struct layer *oldflayer = flayer;
363 struct display *d, *olddisplay = display;
365 if (l->l_width == wi && l->l_height == he)
366 return;
367 p = Layer2Window(l);
369 /* If 'flayer' and 'l' are for the same window, then we will not
370 * restore 'flayer'. */
371 if (oldflayer && (l == oldflayer || Layer2Window(oldflayer) == p))
372 oldflayer = NULL;
374 flayer = l;
376 if (p)
378 /* It's a window layer. Kill the overlays on it in all displays. */
379 for (d = displays; d; d = d->d_next)
380 for (cv = d->d_cvlist; cv; cv = cv->c_next)
382 if (p == Layer2Window(cv->c_layer))
384 /* Canvas 'cv' on display 'd' shows this window. Remove any non-resizable
385 * layers over it. */
386 RESIZE_OR_KILL_LAYERS(cv->c_layer, wi, he);
390 else
392 /* It's a Blank layer. Just kill the non-resizable overlays over it. */
393 RESIZE_OR_KILL_LAYERS(flayer, wi, he);
396 for (display = displays; display; display = display->d_next)
398 if (display == norefdisp)
399 continue;
400 for (cv = D_cvlist; cv; cv = cv->c_next)
401 if (Layer2Window(cv->c_layer) == p)
403 CV_CALL(cv, LayRedisplayLine(-1, -1, -1, 0));
404 RefreshArea(cv->c_xs, cv->c_ys, cv->c_xe, cv->c_ye, 0);
406 if (D_kaablamm)
408 kaablamm();
409 D_kaablamm = 0;
413 /* If we started resizing a non-flayer layer, then restore the flayer.
414 * Otherwise, flayer should already be updated to the topmost foreground layer. */
415 if (oldflayer)
416 flayer = oldflayer;
417 display = olddisplay;
420 static void
421 FreeMline(ml)
422 struct mline *ml;
424 if (ml->image)
425 free(ml->image);
426 if (ml->attr && ml->attr != null)
427 free(ml->attr);
428 #ifdef FONT
429 if (ml->font && ml->font != null)
430 free(ml->font);
431 #endif
432 #ifdef COLOR
433 if (ml->color && ml->color != null)
434 free(ml->color);
435 # ifdef COLORS256
436 if (ml->colorx && ml->colorx != null)
437 free(ml->colorx);
438 # endif
439 #endif
440 *ml = mline_zero;
443 static int
444 AllocMline(ml, w)
445 struct mline *ml;
446 int w;
448 ml->image = malloc(w);
449 ml->attr = null;
450 #ifdef FONT
451 ml->font = null;
452 #endif
453 #ifdef COLOR
454 ml->color = null;
455 # ifdef COLORS256
456 ml->colorx = null;
457 # endif
458 #endif
459 if (ml->image == 0)
460 return -1;
461 return 0;
465 static int
466 BcopyMline(mlf, xf, mlt, xt, l, w)
467 struct mline *mlf, *mlt;
468 int xf, xt, l, w;
470 int r = 0;
472 bcopy((char *)mlf->image + xf, (char *)mlt->image + xt, l);
473 if (mlf->attr != null && mlt->attr == null)
475 if ((mlt->attr = (unsigned char *)calloc(w, 1)) == 0)
476 mlt->attr = null, r = -1;
478 if (mlt->attr != null)
479 bcopy((char *)mlf->attr + xf, (char *)mlt->attr + xt, l);
480 #ifdef FONT
481 if (mlf->font != null && mlt->font == null)
483 if ((mlt->font = (unsigned char *)calloc(w, 1)) == 0)
484 mlt->font = null, r = -1;
486 if (mlt->font != null)
487 bcopy((char *)mlf->font + xf, (char *)mlt->font + xt, l);
488 #endif
489 #ifdef COLOR
490 if (mlf->color != null && mlt->color == null)
492 if ((mlt->color = (unsigned char *)calloc(w, 1)) == 0)
493 mlt->color = null, r = -1;
495 if (mlt->color != null)
496 bcopy((char *)mlf->color + xf, (char *)mlt->color + xt, l);
497 # ifdef COLORS256
498 if (mlf->colorx != null && mlt->colorx == null)
500 if ((mlt->colorx = (unsigned char *)calloc(w, 1)) == 0)
501 mlt->colorx = null, r = -1;
503 if (mlt->colorx != null)
504 bcopy((char *)mlf->colorx + xf, (char *)mlt->colorx + xt, l);
505 # endif
506 #endif
507 return r;
511 static int maxwidth;
513 static void
514 CheckMaxSize(wi)
515 int wi;
517 unsigned char *oldnull = null;
518 unsigned char *oldblank = blank;
519 struct win *p;
520 int i;
521 struct mline *ml;
523 wi = ((wi + 1) + 255) & ~255;
524 if (wi <= maxwidth)
525 return;
526 maxwidth = wi;
527 debug1("New maxwidth: %d\n", maxwidth);
528 blank = (unsigned char *)xrealloc((char *)blank, maxwidth);
529 null = (unsigned char *)xrealloc((char *)null, maxwidth);
530 mline_old.image = (unsigned char *)xrealloc((char *)mline_old.image, maxwidth);
531 mline_old.attr = (unsigned char *)xrealloc((char *)mline_old.attr, maxwidth);
532 #ifdef FONT
533 mline_old.font = (unsigned char *)xrealloc((char *)mline_old.font, maxwidth);
534 #endif
535 #ifdef COLOR
536 mline_old.color = (unsigned char *)xrealloc((char *)mline_old.color, maxwidth);
537 # ifdef COLORS256
538 mline_old.colorx = (unsigned char *)xrealloc((char *)mline_old.colorx, maxwidth);
539 # endif
540 #endif
541 if (!(blank && null && mline_old.image && mline_old.attr IFFONT(&& mline_old.font) IFCOLOR(&& mline_old.color) IFCOLORX(&& mline_old.colorx)))
542 Panic(0, "%s", strnomem);
544 MakeBlankLine(blank, maxwidth);
545 bzero((char *)null, maxwidth);
547 mline_blank.image = blank;
548 mline_blank.attr = null;
549 mline_null.image = null;
550 mline_null.attr = null;
551 #ifdef FONT
552 mline_blank.font = null;
553 mline_null.font = null;
554 #endif
555 #ifdef COLOR
556 mline_blank.color = null;
557 mline_null.color = null;
558 # ifdef COLORS256
559 mline_blank.colorx = null;
560 mline_null.colorx = null;
561 # endif
562 #endif
564 #define RESET_AFC(x, bl) do { if (x == old##bl) x = bl; } while (0)
566 #define RESET_LINES(lines, count) \
567 do { \
568 ml = lines; \
569 for (i = 0; i < count; i++, ml++) \
571 RESET_AFC(ml->image, blank); \
572 RESET_AFC(ml->attr, null); \
573 IFFONT(RESET_AFC(ml->font, null)); \
574 IFCOLOR(RESET_AFC(ml->color, null)); \
575 IFCOLORX(RESET_AFC(ml->colorx, null)); \
577 } while (0)
579 /* We have to run through all windows to substitute
580 * the null and blank references.
582 for (p = windows; p; p = p->w_next)
584 RESET_LINES(p->w_mlines, p->w_height);
586 #ifdef COPY_PASTE
587 RESET_LINES(p->w_hlines, p->w_histheight);
588 RESET_LINES(p->w_alt.hlines, p->w_alt.histheight);
589 #endif
591 RESET_LINES(p->w_alt.mlines, p->w_alt.height);
596 char *
597 xrealloc(mem, len)
598 char *mem;
599 int len;
601 register char *nmem;
603 if (mem == 0)
604 return malloc(len);
605 if ((nmem = realloc(mem, len)))
606 return nmem;
607 free(mem);
608 return (char *)0;
611 static void
612 MakeBlankLine(p, n)
613 register unsigned char *p;
614 register int n;
616 while (n--)
617 *p++ = ' ';
623 #ifdef COPY_PASTE
625 #define OLDWIN(y) ((y < p->w_histheight) \
626 ? &p->w_hlines[(p->w_histidx + y) % p->w_histheight] \
627 : &p->w_mlines[y - p->w_histheight])
629 #define NEWWIN(y) ((y < hi) ? &nhlines[y] : &nmlines[y - hi])
631 #else
633 #define OLDWIN(y) (&p->w_mlines[y])
634 #define NEWWIN(y) (&nmlines[y])
636 #endif
640 ChangeWindowSize(p, wi, he, hi)
641 struct win *p;
642 int wi, he, hi;
644 struct mline *mlf = 0, *mlt = 0, *ml, *nmlines, *nhlines;
645 int fy, ty, l, lx, lf, lt, yy, oty, addone;
646 int ncx, ncy, naka, t;
647 int y, shift;
649 if (wi <= 0 || he <= 0)
650 wi = he = hi = 0;
652 if (p->w_type == W_TYPE_GROUP)
653 return 0;
655 if (wi > 1000)
657 Msg(0, "Window width too large. Truncated to 1000.");
658 wi = 1000;
661 if (he > 1000)
663 Msg(0, "Window height too large. Truncated to 1000.");
664 he = 1000;
667 if (p->w_width == wi && p->w_height == he && p->w_histheight == hi)
669 debug("ChangeWindowSize: No change.\n");
670 return 0;
673 CheckMaxSize(wi);
675 /* XXX */
676 #if 0
677 /* just in case ... */
678 if (wi && (p->w_width != wi || p->w_height != he) && p->w_lay != &p->w_winlay)
680 debug("ChangeWindowSize: No resize because of overlay?\n");
681 return -1;
683 #endif
685 debug("ChangeWindowSize");
686 debug3(" from (%d,%d)+%d", p->w_width, p->w_height, p->w_histheight);
687 debug3(" to(%d,%d)+%d\n", wi, he, hi);
689 fy = p->w_histheight + p->w_height - 1;
690 ty = hi + he - 1;
692 nmlines = nhlines = 0;
693 ncx = 0;
694 ncy = 0;
695 naka = 0;
697 if (wi)
699 if (wi != p->w_width || he != p->w_height)
701 if ((nmlines = (struct mline *)calloc(he, sizeof(struct mline))) == 0)
703 KillWindow(p);
704 Msg(0, "%s", strnomem);
705 return -1;
708 else
710 debug1("image stays the same: %d lines\n", he);
711 nmlines = p->w_mlines;
712 fy -= he;
713 ty -= he;
714 ncx = p->w_x;
715 ncy = p->w_y;
716 naka = p->w_autoaka;
719 #ifdef COPY_PASTE
720 if (hi)
722 if ((nhlines = (struct mline *)calloc(hi, sizeof(struct mline))) == 0)
724 Msg(0, "No memory for history buffer - turned off");
725 hi = 0;
726 ty = he - 1;
729 #endif
731 /* special case: cursor is at magic margin position */
732 addone = 0;
733 if (p->w_width && p->w_x == p->w_width)
735 debug2("Special addone case: %d %d\n", p->w_x, p->w_y);
736 addone = 1;
737 p->w_x--;
740 /* handle the cursor and autoaka lines now if the widths are equal */
741 if (p->w_width == wi)
743 ncx = p->w_x + addone;
744 ncy = p->w_y + he - p->w_height;
745 /* never lose sight of the line with the cursor on it */
746 shift = -ncy;
747 for (yy = p->w_y + p->w_histheight - 1; yy >= 0 && ncy + shift < he; yy--)
749 ml = OLDWIN(yy);
750 if (ml->image[p->w_width] == ' ')
751 break;
752 shift++;
754 if (shift < 0)
755 shift = 0;
756 else
757 debug1("resize: cursor out of bounds, shifting %d\n", shift);
758 ncy += shift;
759 if (p->w_autoaka > 0)
761 naka = p->w_autoaka + he - p->w_height + shift;
762 if (naka < 1 || naka > he)
763 naka = 0;
765 while (shift-- > 0)
767 ml = OLDWIN(fy);
768 FreeMline(ml);
769 fy--;
772 debug2("fy %d ty %d\n", fy, ty);
773 if (fy >= 0)
774 mlf = OLDWIN(fy);
775 if (ty >= 0)
776 mlt = NEWWIN(ty);
778 while (fy >= 0 && ty >= 0)
780 if (p->w_width == wi)
782 /* here is a simple shortcut: just copy over */
783 *mlt = *mlf;
784 *mlf = mline_zero;
785 if (--fy >= 0)
786 mlf = OLDWIN(fy);
787 if (--ty >= 0)
788 mlt = NEWWIN(ty);
789 continue;
792 /* calculate lenght */
793 for (l = p->w_width - 1; l > 0; l--)
794 if (mlf->image[l] != ' ' || mlf->attr[l])
795 break;
796 if (fy == p->w_y + p->w_histheight && l < p->w_x)
797 l = p->w_x; /* cursor is non blank */
798 l++;
799 lf = l;
801 /* add wrapped lines to length */
802 for (yy = fy - 1; yy >= 0; yy--)
804 ml = OLDWIN(yy);
805 if (ml->image[p->w_width] == ' ')
806 break;
807 l += p->w_width;
810 /* rewrap lines */
811 lt = (l - 1) % wi + 1; /* lf is set above */
812 oty = ty;
813 while (l > 0 && fy >= 0 && ty >= 0)
815 lx = lt > lf ? lf : lt;
816 if (mlt->image == 0)
818 if (AllocMline(mlt, wi + 1))
819 goto nomem;
820 MakeBlankLine(mlt->image + lt, wi - lt);
821 mlt->image[wi] = ((oty == ty) ? ' ' : 0);
823 if (BcopyMline(mlf, lf - lx, mlt, lt - lx, lx, wi + 1))
824 goto nomem;
826 /* did we copy the cursor ? */
827 if (fy == p->w_y + p->w_histheight && lf - lx <= p->w_x && lf > p->w_x)
829 ncx = p->w_x + lt - lf + addone;
830 ncy = ty - hi;
831 shift = wi ? -ncy + (l - lx) / wi : 0;
832 if (ty + shift > hi + he - 1)
833 shift = hi + he - 1 - ty;
834 if (shift > 0)
836 debug3("resize: cursor out of bounds, shifting %d [%d/%d]\n", shift, lt - lx, wi);
837 for (y = hi + he - 1; y >= ty; y--)
839 mlt = NEWWIN(y);
840 FreeMline(mlt);
841 if (y - shift < ty)
842 continue;
843 ml = NEWWIN(y - shift);
844 *mlt = *ml;
845 *ml = mline_zero;
847 ncy += shift;
848 ty += shift;
849 mlt = NEWWIN(ty);
850 if (naka > 0)
851 naka = naka + shift > he ? 0 : naka + shift;
853 ASSERT(ncy >= 0);
855 /* did we copy autoaka line ? */
856 if (p->w_autoaka > 0 && fy == p->w_autoaka - 1 + p->w_histheight && lf - lx <= 0)
857 naka = ty - hi >= 0 ? 1 + ty - hi : 0;
859 lf -= lx;
860 lt -= lx;
861 l -= lx;
862 if (lf == 0)
864 FreeMline(mlf);
865 lf = p->w_width;
866 if (--fy >= 0)
867 mlf = OLDWIN(fy);
869 if (lt == 0)
871 lt = wi;
872 if (--ty >= 0)
873 mlt = NEWWIN(ty);
876 ASSERT(l != 0 || fy == yy);
878 while (fy >= 0)
880 FreeMline(mlf);
881 if (--fy >= 0)
882 mlf = OLDWIN(fy);
884 while (ty >= 0)
886 if (AllocMline(mlt, wi + 1))
887 goto nomem;
888 MakeBlankLine(mlt->image, wi + 1);
889 if (--ty >= 0)
890 mlt = NEWWIN(ty);
893 #ifdef DEBUG
894 if (nmlines != p->w_mlines)
895 for (fy = 0; fy < p->w_height + p->w_histheight; fy++)
897 ml = OLDWIN(fy);
898 ASSERT(ml->image == 0);
900 #endif
902 if (p->w_mlines && p->w_mlines != nmlines)
903 free((char *)p->w_mlines);
904 p->w_mlines = nmlines;
905 #ifdef COPY_PASTE
906 if (p->w_hlines && p->w_hlines != nhlines)
907 free((char *)p->w_hlines);
908 p->w_hlines = nhlines;
909 #endif
910 nmlines = nhlines = 0;
912 /* change tabs */
913 if (p->w_width != wi)
915 if (wi)
917 t = p->w_tabs ? p->w_width : 0;
918 p->w_tabs = xrealloc(p->w_tabs, wi + 1);
919 if (p->w_tabs == 0)
921 nomem:
922 if (nmlines)
924 for (ty = he + hi - 1; ty >= 0; ty--)
926 mlt = NEWWIN(ty);
927 FreeMline(mlt);
929 if (nmlines && p->w_mlines != nmlines)
930 free((char *)nmlines);
931 #ifdef COPY_PASTE
932 if (nhlines && p->w_hlines != nhlines)
933 free((char *)nhlines);
934 #endif
936 KillWindow(p);
937 Msg(0, "%s", strnomem);
938 return -1;
940 for (; t < wi; t++)
941 p->w_tabs[t] = t && !(t & 7) ? 1 : 0;
942 p->w_tabs[wi] = 0;
944 else
946 if (p->w_tabs)
947 free(p->w_tabs);
948 p->w_tabs = 0;
952 /* Change w_saved.y - this is only an estimate... */
953 p->w_saved.y += ncy - p->w_y;
955 p->w_x = ncx;
956 p->w_y = ncy;
957 if (p->w_autoaka > 0)
958 p->w_autoaka = naka;
960 /* do sanity checks */
961 if (p->w_x > wi)
962 p->w_x = wi;
963 if (p->w_y >= he)
964 p->w_y = he - 1;
965 if (p->w_saved.x > wi)
966 p->w_saved.x = wi;
967 if (p->w_saved.y < 0)
968 p->w_saved.y = 0;
969 if (p->w_saved.y >= he)
970 p->w_saved.y = he - 1;
971 if (p->w_alt.cursor.x > wi)
972 p->w_alt.cursor.x = wi;
973 if (p->w_alt.cursor.y >= he)
974 p->w_alt.cursor.y = he - 1;
976 /* reset scrolling region */
977 p->w_top = 0;
978 p->w_bot = he - 1;
980 /* signal new size to window */
981 #ifdef TIOCSWINSZ
982 if (wi && (p->w_width != wi || p->w_height != he)
983 && p->w_width != 0 && p->w_height != 0 && p->w_ptyfd >= 0 && p->w_pid)
985 glwz.ws_col = wi;
986 glwz.ws_row = he;
987 debug("Setting pty winsize.\n");
988 if (ioctl(p->w_ptyfd, TIOCSWINSZ, (char *)&glwz))
989 debug2("SetPtySize: errno %d (fd:%d)\n", errno, p->w_ptyfd);
991 #endif /* TIOCSWINSZ */
993 /* store new size */
994 p->w_width = wi;
995 p->w_height = he;
996 #ifdef COPY_PASTE
997 p->w_histidx = 0;
998 p->w_histheight = hi;
999 #endif
1001 #ifdef BUILTIN_TELNET
1002 if (p->w_type == W_TYPE_TELNET)
1003 TelWindowSize(p);
1004 #endif
1006 #ifdef DEBUG
1007 /* Test if everything was ok */
1008 for (fy = 0; fy < p->w_height + p->w_histheight; fy++)
1010 ml = OLDWIN(fy);
1011 ASSERT(ml->image);
1012 # ifdef UTF8
1013 if (p->w_encoding == UTF8)
1015 for (l = 0; l < p->w_width; l++)
1016 ASSERT(ml->image[l] >= ' ' || ml->font[l]);
1018 else
1019 #endif
1020 for (l = 0; l < p->w_width; l++)
1021 ASSERT(ml->image[l] >= ' ');
1023 #endif
1024 return 0;
1027 void
1028 FreeAltScreen(p)
1029 struct win *p;
1031 int i;
1033 if (p->w_alt.mlines)
1035 for (i = 0; i < p->w_alt.height; i++)
1036 FreeMline(p->w_alt.mlines + i);
1037 free(p->w_alt.mlines);
1039 p->w_alt.mlines = 0;
1040 p->w_alt.width = 0;
1041 p->w_alt.height = 0;
1042 #ifdef COPY_PASTE
1043 if (p->w_alt.hlines)
1045 for (i = 0; i < p->w_alt.histheight; i++)
1046 FreeMline(p->w_alt.hlines + i);
1047 free(p->w_alt.hlines);
1049 p->w_alt.hlines = 0;
1050 p->w_alt.histidx = 0;
1051 #endif
1052 p->w_alt.histheight = 0;
1055 static void
1056 SwapAltScreen(p)
1057 struct win *p;
1059 struct mline *ml;
1060 int t;
1062 #define SWAP(item, t) do { (t) = p->w_alt. item; p->w_alt. item = p->w_##item; p->w_##item = (t); } while (0)
1064 SWAP(mlines, ml);
1065 SWAP(width, t);
1066 SWAP(height, t);
1067 SWAP(histheight, t);
1069 #ifdef COPY_PASTE
1070 SWAP(hlines, ml);
1071 SWAP(histidx, t);
1072 #endif
1073 #undef SWAP
1076 void
1077 EnterAltScreen(p)
1078 struct win *p;
1080 if (!p->w_alt.on)
1082 /* If not already using the alternate screen buffer, then create
1083 a new one and swap it with the 'real' screen buffer. */
1084 FreeAltScreen(p);
1085 SwapAltScreen(p);
1087 else
1089 /* Already using the alternate buffer. Just clear the screen. To do so, it
1090 is only necessary to reset the height(s) without resetting the width. */
1091 p->w_height = 0;
1092 p->w_histheight = 0;
1094 ChangeWindowSize(p, p->w_alt.width, p->w_alt.height, p->w_alt.histheight);
1095 p->w_alt.on = 1;
1098 void
1099 LeaveAltScreen(p)
1100 struct win *p;
1102 if (!p->w_alt.on)
1103 return;
1104 SwapAltScreen(p);
1105 ChangeWindowSize(p, p->w_alt.width, p->w_alt.height, p->w_alt.histheight);
1106 FreeAltScreen(p);
1107 p->w_alt.on = 0;