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)
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>
32 #include <sys/ioctl.h>
37 # include <sys/sioctl.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)
65 static struct mline mline_zero
= {
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
89 CheckScreenSize(change_flag
)
96 debug("CheckScreenSize: No display -> no check.\n");
100 if (ioctl(D_userfd
, TIOCGWINSZ
, (char *)&glwz
) != 0)
102 debug2("CheckScreenSize: ioctl(%d, TIOCGWINSZ) errno %d\n", D_userfd
, errno
);
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
);
131 if (D_width
== wi
&& D_height
== he
)
133 debug("CheckScreenSize: No change -> return.\n");
140 ChangeScreenSize(wi
, he
, change_flag
);
141 /* XXX Redisplay logic */
143 if (change_flag
== 1)
144 Redisplay(D_fore
? D_fore
->w_norefresh
: 0);
149 ChangeScreenSize(wi
, he
, change_fore
)
157 debug2("ChangeScreenSize from (%d,%d) ", D_width
, D_height
);
158 debug3("to (%d,%d) (change_fore: %d)\n",wi
, he
, change_fore
);
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;
167 RecreateCanvasChain();
168 RethinkDisplayViewports();
173 D_fore
= Layer2Window(D_forecv
->c_layer
);
186 if (D_CZ0
&& (wi
== Z0width
|| wi
== Z1width
) &&
187 (D_CO
== Z0width
|| D_CO
== Z1width
))
193 debug2("Default size: (%d,%d)\n", D_defwidth
, D_defheight
);
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
);
204 if (D_CZ0
&& p
->w_width
!= wi
&& (wi
== Z0width
|| wi
== Z1width
))
206 if (p
->w_width
> (Z0width
+ Z1width
) / 2)
212 if (p
->w_savelayer
&& p
->w_savelayer
->l_cvlist
== 0)
213 ResizeLayer(p
->w_savelayer
, wwi
, he
, 0);
215 ChangeWindowSize(p
, wwi
, he
, p
->w_histheight
);
222 ResizeLayersToCanvases()
228 debug("ResizeLayersToCanvases\n");
230 for (cv
= D_cvlist
; cv
; cv
= cv
->c_next
)
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");
242 if (!MayResizeLayer(l
))
244 debug("may not resize.\n");
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
;
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
;
283 RethinkViewportOffsets(cv
);
299 debug("MayResizeLayer:\n");
300 for (; l
; l
= l
->l_next
)
303 if (++cvs
> 1 || l
->l_cvlist
->c_lnext
)
305 debug1("may not - cvs %d\n", cvs
);
309 debug("may resize\n");
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...
323 Msg(0, "Aborted because of window size change.");
327 ResizeLayer(l
, wi
, he
, norefdisp
)
330 struct display
*norefdisp
;
334 struct layer
*oldflayer
= flayer
;
335 struct display
*d
, *olddisplay
= display
;
337 if (l
->l_width
== wi
&& l
->l_height
== he
)
341 if (oldflayer
&& (l
== oldflayer
|| Layer2Window(oldflayer
) == p
))
342 while (oldflayer
->l_next
)
343 oldflayer
= oldflayer
->l_next
;
347 for (d
= displays
; d
; d
= d
->d_next
)
348 for (cv
= d
->d_cvlist
; cv
; cv
= cv
->c_next
)
350 if (p
== Layer2Window(cv
->c_layer
))
352 flayer
= cv
->c_layer
;
355 while (flayer
->l_next
)
362 if (p
== 0 && flayer
->l_next
&& flayer
->l_next
->l_next
== 0 && LayResize(wi
, he
) == 0)
364 flayer
= flayer
->l_next
;
371 for (cv
= flayer
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
372 cv
->c_display
->d_kaablamm
= 1;
373 while (flayer
->l_next
)
377 flayer
= &p
->w_layer
;
379 /* now everybody is on flayer, redisplay */
381 for (display
= displays
; display
; display
= display
->d_next
)
383 if (display
== norefdisp
)
385 for (cv
= D_cvlist
; cv
; cv
= cv
->c_next
)
386 if (cv
->c_layer
== l
)
388 CV_CALL(cv
, LayRedisplayLine(-1, -1, -1, 0));
389 RefreshArea(cv
->c_xs
, cv
->c_ys
, cv
->c_xe
, cv
->c_ye
, 0);
398 display
= olddisplay
;
408 if (ml
->attr
&& ml
->attr
!= null
)
411 if (ml
->font
&& ml
->font
!= null
)
415 if (ml
->color
&& ml
->color
!= null
)
418 if (ml
->colorx
&& ml
->colorx
!= null
)
430 ml
->image
= malloc(w
);
448 BcopyMline(mlf
, xf
, mlt
, xt
, l
, w
)
449 struct mline
*mlf
, *mlt
;
454 bcopy((char *)mlf
->image
+ xf
, (char *)mlt
->image
+ xt
, l
);
455 if (mlf
->attr
!= null
&& mlt
->attr
== null
)
457 if ((mlt
->attr
= (unsigned char *)calloc(w
, 1)) == 0)
458 mlt
->attr
= null
, r
= -1;
460 if (mlt
->attr
!= null
)
461 bcopy((char *)mlf
->attr
+ xf
, (char *)mlt
->attr
+ xt
, l
);
463 if (mlf
->font
!= null
&& mlt
->font
== null
)
465 if ((mlt
->font
= (unsigned char *)calloc(w
, 1)) == 0)
466 mlt
->font
= null
, r
= -1;
468 if (mlt
->font
!= null
)
469 bcopy((char *)mlf
->font
+ xf
, (char *)mlt
->font
+ xt
, l
);
472 if (mlf
->color
!= null
&& mlt
->color
== null
)
474 if ((mlt
->color
= (unsigned char *)calloc(w
, 1)) == 0)
475 mlt
->color
= null
, r
= -1;
477 if (mlt
->color
!= null
)
478 bcopy((char *)mlf
->color
+ xf
, (char *)mlt
->color
+ xt
, l
);
480 if (mlf
->colorx
!= null
&& mlt
->colorx
== null
)
482 if ((mlt
->colorx
= (unsigned char *)calloc(w
, 1)) == 0)
483 mlt
->colorx
= null
, r
= -1;
485 if (mlt
->colorx
!= null
)
486 bcopy((char *)mlf
->colorx
+ xf
, (char *)mlt
->colorx
+ xt
, l
);
499 unsigned char *oldnull
= null
;
504 wi
= ((wi
+ 1) + 255) & ~255;
508 debug1("New maxwidth: %d\n", maxwidth
);
509 blank
= (unsigned char *)xrealloc((char *)blank
, maxwidth
);
510 null
= (unsigned char *)xrealloc((char *)null
, maxwidth
);
511 mline_old
.image
= (unsigned char *)xrealloc((char *)mline_old
.image
, maxwidth
);
512 mline_old
.attr
= (unsigned char *)xrealloc((char *)mline_old
.attr
, maxwidth
);
514 mline_old
.font
= (unsigned char *)xrealloc((char *)mline_old
.font
, maxwidth
);
517 mline_old
.color
= (unsigned char *)xrealloc((char *)mline_old
.color
, maxwidth
);
519 mline_old
.colorx
= (unsigned char *)xrealloc((char *)mline_old
.color
, maxwidth
);
522 if (!(blank
&& null
&& mline_old
.image
&& mline_old
.attr
IFFONT(&& mline_old
.font
) IFCOLOR(&& mline_old
.color
) IFCOLORX(&& mline_old
.colorx
)))
525 MakeBlankLine(blank
, maxwidth
);
526 bzero((char *)null
, maxwidth
);
528 mline_blank
.image
= blank
;
529 mline_blank
.attr
= null
;
530 mline_null
.image
= null
;
531 mline_null
.attr
= null
;
533 mline_blank
.font
= null
;
534 mline_null
.font
= null
;
537 mline_blank
.color
= null
;
538 mline_null
.color
= null
;
540 mline_blank
.colorx
= null
;
541 mline_null
.colorx
= null
;
545 /* We have to run through all windows to substitute
546 * the null references.
548 for (p
= windows
; p
; p
= p
->w_next
)
551 for (i
= 0; i
< p
->w_height
; i
++, ml
++)
553 if (ml
->attr
== oldnull
)
556 if (ml
->font
== oldnull
)
560 if (ml
->color
== oldnull
)
563 if (ml
->colorx
== oldnull
)
570 for (i
= 0; i
< p
->w_histheight
; i
++, ml
++)
572 if (ml
->attr
== oldnull
)
575 if (ml
->font
== oldnull
)
579 if (ml
->color
== oldnull
)
582 if (ml
->colorx
== oldnull
)
601 if ((nmem
= realloc(mem
, len
)))
609 register unsigned char *p
;
621 #define OLDWIN(y) ((y < p->w_histheight) \
622 ? &p->w_hlines[(p->w_histidx + y) % p->w_histheight] \
623 : &p->w_mlines[y - p->w_histheight])
625 #define NEWWIN(y) ((y < hi) ? &nhlines[y] : &nmlines[y - hi])
629 #define OLDWIN(y) (&p->w_mlines[y])
630 #define NEWWIN(y) (&nmlines[y])
636 ChangeWindowSize(p
, wi
, he
, hi
)
640 struct mline
*mlf
= 0, *mlt
= 0, *ml
, *nmlines
, *nhlines
;
641 int fy
, ty
, l
, lx
, lf
, lt
, yy
, oty
, addone
;
642 int ncx
, ncy
, naka
, t
;
648 if (p
->w_type
== W_TYPE_GROUP
)
650 if (p
->w_width
== wi
&& p
->w_height
== he
&& p
->w_histheight
== hi
)
652 debug("ChangeWindowSize: No change.\n");
660 /* just in case ... */
661 if (wi
&& (p
->w_width
!= wi
|| p
->w_height
!= he
) && p
->w_lay
!= &p
->w_winlay
)
663 debug("ChangeWindowSize: No resize because of overlay?\n");
668 debug("ChangeWindowSize");
669 debug3(" from (%d,%d)+%d", p
->w_width
, p
->w_height
, p
->w_histheight
);
670 debug3(" to(%d,%d)+%d\n", wi
, he
, hi
);
672 fy
= p
->w_histheight
+ p
->w_height
- 1;
675 nmlines
= nhlines
= 0;
682 if (wi
!= p
->w_width
|| he
!= p
->w_height
)
684 if ((nmlines
= (struct mline
*)calloc(he
, sizeof(struct mline
))) == 0)
693 debug1("image stays the same: %d lines\n", he
);
694 nmlines
= p
->w_mlines
;
705 if ((nhlines
= (struct mline
*)calloc(hi
, sizeof(struct mline
))) == 0)
707 Msg(0, "No memory for history buffer - turned off");
714 /* special case: cursor is at magic margin position */
716 if (p
->w_width
&& p
->w_x
== p
->w_width
)
718 debug2("Special addone case: %d %d\n", p
->w_x
, p
->w_y
);
723 /* handle the cursor and autoaka lines now if the widths are equal */
724 if (p
->w_width
== wi
)
726 ncx
= p
->w_x
+ addone
;
727 ncy
= p
->w_y
+ he
- p
->w_height
;
728 /* never lose sight of the line with the cursor on it */
730 for (yy
= p
->w_y
+ p
->w_histheight
- 1; yy
>= 0 && ncy
+ shift
< he
; yy
--)
733 if (ml
->image
[p
->w_width
] == ' ')
740 debug1("resize: cursor out of bounds, shifting %d\n", shift
);
742 if (p
->w_autoaka
> 0)
744 naka
= p
->w_autoaka
+ he
- p
->w_height
+ shift
;
745 if (naka
< 1 || naka
> he
)
755 debug2("fy %d ty %d\n", fy
, ty
);
761 while (fy
>= 0 && ty
>= 0)
763 if (p
->w_width
== wi
)
765 /* here is a simple shortcut: just copy over */
775 /* calculate lenght */
776 for (l
= p
->w_width
- 1; l
> 0; l
--)
777 if (mlf
->image
[l
] != ' ' || mlf
->attr
[l
])
779 if (fy
== p
->w_y
+ p
->w_histheight
&& l
< p
->w_x
)
780 l
= p
->w_x
; /* cursor is non blank */
784 /* add wrapped lines to length */
785 for (yy
= fy
- 1; yy
>= 0; yy
--)
788 if (ml
->image
[p
->w_width
] == ' ')
794 lt
= (l
- 1) % wi
+ 1; /* lf is set above */
796 while (l
> 0 && fy
>= 0 && ty
>= 0)
798 lx
= lt
> lf
? lf
: lt
;
801 if (AllocMline(mlt
, wi
+ 1))
803 MakeBlankLine(mlt
->image
+ lt
, wi
- lt
);
804 mlt
->image
[wi
] = ((oty
== ty
) ? ' ' : 0);
806 if (BcopyMline(mlf
, lf
- lx
, mlt
, lt
- lx
, lx
, wi
+ 1))
809 /* did we copy the cursor ? */
810 if (fy
== p
->w_y
+ p
->w_histheight
&& lf
- lx
<= p
->w_x
&& lf
> p
->w_x
)
812 ncx
= p
->w_x
+ lt
- lf
+ addone
;
814 shift
= wi
? -ncy
+ (l
- lx
) / wi
: 0;
815 if (ty
+ shift
> hi
+ he
- 1)
816 shift
= hi
+ he
- 1 - ty
;
819 debug3("resize: cursor out of bounds, shifting %d [%d/%d]\n", shift
, lt
- lx
, wi
);
820 for (y
= hi
+ he
- 1; y
>= ty
; y
--)
826 ml
= NEWWIN(y
- shift
);
834 naka
= naka
+ shift
> he
? 0 : naka
+ shift
;
838 /* did we copy autoaka line ? */
839 if (p
->w_autoaka
> 0 && fy
== p
->w_autoaka
- 1 + p
->w_histheight
&& lf
- lx
<= 0)
840 naka
= ty
- hi
>= 0 ? 1 + ty
- hi
: 0;
859 ASSERT(l
!= 0 || fy
== yy
);
869 if (AllocMline(mlt
, wi
+ 1))
871 MakeBlankLine(mlt
->image
, wi
+ 1);
877 if (nmlines
!= p
->w_mlines
)
878 for (fy
= 0; fy
< p
->w_height
+ p
->w_histheight
; fy
++)
881 ASSERT(ml
->image
== 0);
885 if (p
->w_mlines
&& p
->w_mlines
!= nmlines
)
886 free((char *)p
->w_mlines
);
887 p
->w_mlines
= nmlines
;
889 if (p
->w_hlines
&& p
->w_hlines
!= nhlines
)
890 free((char *)p
->w_hlines
);
891 p
->w_hlines
= nhlines
;
893 nmlines
= nhlines
= 0;
896 if (p
->w_width
!= wi
)
900 t
= p
->w_tabs
? p
->w_width
: 0;
901 p
->w_tabs
= xrealloc(p
->w_tabs
, wi
+ 1);
907 for (ty
= he
+ hi
- 1; ty
>= 0; ty
--)
912 if (nmlines
&& p
->w_mlines
!= nmlines
)
913 free((char *)nmlines
);
915 if (nhlines
&& p
->w_hlines
!= nhlines
)
916 free((char *)nhlines
);
924 p
->w_tabs
[t
] = t
&& !(t
& 7) ? 1 : 0;
935 /* Change w_Saved_y - this is only an estimate... */
936 p
->w_Saved_y
+= ncy
- p
->w_y
;
940 if (p
->w_autoaka
> 0)
943 /* do sanity checks */
948 if (p
->w_Saved_x
> wi
)
950 if (p
->w_Saved_y
< 0)
952 if (p
->w_Saved_y
>= he
)
953 p
->w_Saved_y
= he
- 1;
955 /* reset scrolling region */
959 /* signal new size to window */
961 if (wi
&& (p
->w_width
!= wi
|| p
->w_height
!= he
)
962 && p
->w_width
!= 0 && p
->w_height
!= 0 && p
->w_ptyfd
>= 0 && p
->w_pid
)
966 debug("Setting pty winsize.\n");
967 if (ioctl(p
->w_ptyfd
, TIOCSWINSZ
, (char *)&glwz
))
968 debug2("SetPtySize: errno %d (fd:%d)\n", errno
, p
->w_ptyfd
);
970 #endif /* TIOCSWINSZ */
977 p
->w_histheight
= hi
;
980 #ifdef BUILTIN_TELNET
981 if (p
->w_type
== W_TYPE_TELNET
)
986 /* Test if everything was ok */
987 for (fy
= 0; fy
< p
->w_height
+ p
->w_histheight
; fy
++)
992 if (p
->w_encoding
== UTF8
)
994 for (l
= 0; l
< p
->w_width
; l
++)
995 ASSERT(ml
->image
[l
] >= ' ' || ml
->font
[l
]);
999 for (l
= 0; l
< p
->w_width
; l
++)
1000 ASSERT(ml
->image
[l
] >= ' ');
1012 if (p
->w_alt_mlines
)
1014 for (i
= 0; i
< p
->w_alt_height
; i
++)
1015 FreeMline(p
->w_alt_mlines
+ i
);
1016 free(p
->w_alt_mlines
);
1018 p
->w_alt_mlines
= 0;
1020 p
->w_alt_height
= 0;
1024 if (p
->w_alt_hlines
)
1026 for (i
= 0; i
< p
->w_alt_histheight
; i
++)
1027 FreeMline(p
->w_alt_hlines
+ i
);
1028 free(p
->w_alt_hlines
);
1030 p
->w_alt_hlines
= 0;
1031 p
->w_alt_histidx
= 0;
1033 p
->w_alt_histheight
= 0;
1043 ml
= p
->w_alt_mlines
; p
->w_alt_mlines
= p
->w_mlines
; p
->w_mlines
= ml
;
1044 t
= p
->w_alt_width
; p
->w_alt_width
= p
->w_width
; p
->w_width
= t
;
1045 t
= p
->w_alt_height
; p
->w_alt_height
= p
->w_height
; p
->w_height
= t
;
1046 t
= p
->w_alt_histheight
; p
->w_alt_histheight
= p
->w_histheight
; p
->w_histheight
= t
;
1047 t
= p
->w_alt_x
; p
->w_alt_x
= p
->w_x
; p
->w_x
= t
;
1048 t
= p
->w_alt_y
; p
->w_alt_y
= p
->w_y
; p
->w_y
= t
;
1050 ml
= p
->w_alt_hlines
; p
->w_alt_hlines
= p
->w_hlines
; p
->w_hlines
= ml
;
1051 t
= p
->w_alt_histidx
; p
->w_alt_histidx
= p
->w_histidx
; p
->w_histidx
= t
;
1059 int ox
= p
->w_x
, oy
= p
->w_y
;
1062 ChangeWindowSize(p
, p
->w_alt_width
, p
->w_alt_height
, p
->w_alt_histheight
);
1071 if (!p
->w_alt_mlines
)
1074 ChangeWindowSize(p
, p
->w_alt_width
, p
->w_alt_height
, p
->w_alt_histheight
);