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
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)
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.
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
21 ****************************************************************
24 #include <sys/types.h>
27 #include <sys/ioctl.h>
32 # include <sys/sioctl.h>
40 static void CheckMaxSize
__P((int));
41 static void FreeMline
__P((struct mline
*));
42 static int AllocMline
__P((struct mline
*ml
, int));
43 static void MakeBlankLine
__P((unsigned char *, int));
44 static void kaablamm
__P((void));
45 static int BcopyMline
__P((struct mline
*, int, struct mline
*, int, int, int));
46 static void SwapAltScreen
__P((struct win
*));
48 extern struct layer
*flayer
;
49 extern struct display
*display
, *displays
;
50 extern unsigned char *blank
, *null
;
51 extern struct mline mline_blank
, mline_null
, mline_old
;
52 extern struct win
*windows
;
53 extern int Z0width
, Z1width
;
54 extern int captionalways
;
56 #if defined(TIOCGWINSZ) || defined(TIOCSWINSZ)
60 static struct mline mline_zero
= {
75 * ChangeFlag: 0: try to modify no window
76 * 1: modify fore (and try to modify no other) + redisplay
77 * 2: modify all windows
79 * Note: Activate() is only called if change_flag == 1
80 * i.e. on a WINCH event
84 CheckScreenSize(change_flag
)
91 debug("CheckScreenSize: No display -> no check.\n");
95 if (ioctl(D_userfd
, TIOCGWINSZ
, (char *)&glwz
) != 0)
97 debug2("CheckScreenSize: ioctl(%d, TIOCGWINSZ) errno %d\n", D_userfd
, errno
);
115 debug2("CheckScreenSize: screen is (%d,%d)\n", wi
, he
);
117 #if 0 /* XXX: Fixme */
118 if (change_flag
== 2)
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
);
126 if (D_width
== wi
&& D_height
== he
)
128 debug("CheckScreenSize: No change -> return.\n");
135 ChangeScreenSize(wi
, he
, change_flag
);
136 /* XXX Redisplay logic */
138 if (change_flag
== 1)
139 Redisplay(D_fore
? D_fore
->w_norefresh
: 0);
144 ChangeScreenSize(wi
, he
, change_fore
)
152 debug2("ChangeScreenSize from (%d,%d) ", D_width
, D_height
);
153 debug3("to (%d,%d) (change_fore: %d)\n",wi
, he
, change_fore
);
157 cv
->c_ye
= he
- 1 - ((cv
->c_slperp
&& cv
->c_slperp
->c_slnext
) || captionalways
) - (D_has_hstatus
== HSTATUS_LASTLINE
);
161 RecreateCanvasChain();
162 RethinkDisplayViewports();
167 D_fore
= Layer2Window(D_forecv
->c_layer
);
180 if (D_CZ0
&& (wi
== Z0width
|| wi
== Z1width
) &&
181 (D_CO
== Z0width
|| D_CO
== Z1width
))
187 debug2("Default size: (%d,%d)\n", D_defwidth
, D_defheight
);
189 ResizeLayersToCanvases();
190 if (change_fore
== 2 && D_CWS
== NULL
&& displays
->d_next
== 0)
192 /* adapt all windows - to be removed ? */
193 for (p
= windows
; p
; p
= p
->w_next
)
195 debug1("Trying to change window %d.\n", p
->w_number
);
198 if (D_CZ0
&& p
->w_width
!= wi
&& (wi
== Z0width
|| wi
== Z1width
))
200 if (p
->w_width
> (Z0width
+ Z1width
) / 2)
206 if (p
->w_savelayer
&& p
->w_savelayer
->l_cvlist
== 0)
207 ResizeLayer(p
->w_savelayer
, wwi
, he
, 0);
209 ChangeWindowSize(p
, wwi
, he
, p
->w_histheight
);
216 ResizeLayersToCanvases()
222 debug("ResizeLayersToCanvases\n");
224 for (cv
= D_cvlist
; cv
; cv
= cv
->c_next
)
229 debug("Doing canvas: ");
230 if (l
->l_width
== cv
->c_xe
- cv
->c_xs
+ 1 &&
231 l
->l_height
== cv
->c_ye
- cv
->c_ys
+ 1)
233 debug("already fitting.\n");
236 if (!MayResizeLayer(l
))
238 debug("may not resize.\n");
242 debug("doing resize.\n");
243 ResizeLayer(l
, cv
->c_xe
- cv
->c_xs
+ 1, cv
->c_ye
- cv
->c_ys
+ 1, display
);
246 /* normalize window, see screen.c */
247 lx
= cv
->c_layer
->l_x
;
248 ly
= cv
->c_layer
->l_y
;
249 if (ly
+ cv
->c_yoff
< cv
->c_ys
)
251 cv
->c_yoff
= cv
->c_ys
- ly
;
252 RethinkViewportOffsets(cv
);
254 else if (ly
+ cv
->c_yoff
> cv
->c_ye
)
256 cv
->c_yoff
= cv
->c_ye
- ly
;
257 RethinkViewportOffsets(cv
);
259 if (lx
+ cv
->c_xoff
< cv
->c_xs
)
261 int n
= cv
->c_xs
- (lx
+ cv
->c_xoff
);
262 if (n
< (cv
->c_xe
- cv
->c_xs
+ 1) / 2)
263 n
= (cv
->c_xe
- cv
->c_xs
+ 1) / 2;
264 if (cv
->c_xoff
+ n
> cv
->c_xs
)
265 n
= cv
->c_xs
- cv
->c_xoff
;
267 RethinkViewportOffsets(cv
);
269 else if (lx
+ cv
->c_xoff
> cv
->c_xe
)
271 int n
= lx
+ cv
->c_xoff
- cv
->c_xe
;
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_layer
->l_width
- 1 < cv
->c_xe
)
275 n
= cv
->c_xoff
+ cv
->c_layer
->l_width
- 1 - cv
->c_xe
;
277 RethinkViewportOffsets(cv
);
293 debug("MayResizeLayer:\n");
294 for (; l
; l
= l
->l_next
)
297 if (++cvs
> 1 || l
->l_cvlist
->c_lnext
)
299 debug1("may not - cvs %d\n", cvs
);
303 debug("may resize\n");
308 * Easy implementation: rely on the fact that the only layers
309 * supporting resize are Win and Blank. So just kill all overlays.
311 * This is a lot harder if done the right way...
317 Msg(0, "Aborted because of window size change.");
321 ResizeLayer(l
, wi
, he
, norefdisp
)
324 struct display
*norefdisp
;
328 struct layer
*oldflayer
= flayer
;
329 struct display
*d
, *olddisplay
= display
;
331 if (l
->l_width
== wi
&& l
->l_height
== he
)
335 if (oldflayer
&& (l
== oldflayer
|| Layer2Window(oldflayer
) == p
))
336 while (oldflayer
->l_next
)
337 oldflayer
= oldflayer
->l_next
;
341 for (d
= displays
; d
; d
= d
->d_next
)
342 for (cv
= d
->d_cvlist
; cv
; cv
= cv
->c_next
)
344 if (p
== Layer2Window(cv
->c_layer
))
346 flayer
= cv
->c_layer
;
349 while (flayer
->l_next
)
356 if (p
== 0 && flayer
->l_next
&& flayer
->l_next
->l_next
== 0 && LayResize(wi
, he
) == 0)
358 flayer
= flayer
->l_next
;
365 for (cv
= flayer
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
366 cv
->c_display
->d_kaablamm
= 1;
367 while (flayer
->l_next
)
371 flayer
= &p
->w_layer
;
373 /* now everybody is on flayer, redisplay */
375 for (display
= displays
; display
; display
= display
->d_next
)
377 if (display
== norefdisp
)
379 for (cv
= D_cvlist
; cv
; cv
= cv
->c_next
)
380 if (cv
->c_layer
== l
)
382 CV_CALL(cv
, LayRedisplayLine(-1, -1, -1, 0));
383 RefreshArea(cv
->c_xs
, cv
->c_ys
, cv
->c_xe
, cv
->c_ye
, 0);
392 display
= olddisplay
;
402 if (ml
->attr
&& ml
->attr
!= null
)
405 if (ml
->font
&& ml
->font
!= null
)
409 if (ml
->color
&& ml
->color
!= null
)
412 if (ml
->colorx
&& ml
->colorx
!= null
)
424 ml
->image
= malloc(w
);
442 BcopyMline(mlf
, xf
, mlt
, xt
, l
, w
)
443 struct mline
*mlf
, *mlt
;
448 bcopy((char *)mlf
->image
+ xf
, (char *)mlt
->image
+ xt
, l
);
449 if (mlf
->attr
!= null
&& mlt
->attr
== null
)
451 if ((mlt
->attr
= (unsigned char *)malloc(w
)) == 0)
452 mlt
->attr
= null
, r
= -1;
453 bzero((char *)mlt
->attr
, w
);
455 if (mlt
->attr
!= null
)
456 bcopy((char *)mlf
->attr
+ xf
, (char *)mlt
->attr
+ xt
, l
);
458 if (mlf
->font
!= null
&& mlt
->font
== null
)
460 if ((mlt
->font
= (unsigned char *)malloc(w
)) == 0)
461 mlt
->font
= null
, r
= -1;
462 bzero((char *)mlt
->font
, w
);
464 if (mlt
->font
!= null
)
465 bcopy((char *)mlf
->font
+ xf
, (char *)mlt
->font
+ xt
, l
);
468 if (mlf
->color
!= null
&& mlt
->color
== null
)
470 if ((mlt
->color
= (unsigned char *)malloc(w
)) == 0)
471 mlt
->color
= null
, r
= -1;
472 bzero((char *)mlt
->color
, w
);
474 if (mlt
->color
!= null
)
475 bcopy((char *)mlf
->color
+ xf
, (char *)mlt
->color
+ xt
, l
);
477 if (mlf
->colorx
!= null
&& mlt
->colorx
== null
)
479 if ((mlt
->colorx
= (unsigned char *)malloc(w
)) == 0)
480 mlt
->colorx
= null
, r
= -1;
481 bzero((char *)mlt
->colorx
, w
);
483 if (mlt
->colorx
!= null
)
484 bcopy((char *)mlf
->colorx
+ xf
, (char *)mlt
->colorx
+ xt
, l
);
497 unsigned char *oldnull
= null
;
502 wi
= ((wi
+ 1) + 255) & ~255;
506 debug1("New maxwidth: %d\n", maxwidth
);
507 blank
= (unsigned char *)xrealloc((char *)blank
, maxwidth
);
508 null
= (unsigned char *)xrealloc((char *)null
, maxwidth
);
509 mline_old
.image
= (unsigned char *)xrealloc((char *)mline_old
.image
, maxwidth
);
510 mline_old
.attr
= (unsigned char *)xrealloc((char *)mline_old
.attr
, maxwidth
);
512 mline_old
.font
= (unsigned char *)xrealloc((char *)mline_old
.font
, maxwidth
);
515 mline_old
.color
= (unsigned char *)xrealloc((char *)mline_old
.color
, maxwidth
);
517 mline_old
.colorx
= (unsigned char *)xrealloc((char *)mline_old
.color
, maxwidth
);
520 if (!(blank
&& null
&& mline_old
.image
&& mline_old
.attr
IFFONT(&& mline_old
.font
) IFCOLOR(&& mline_old
.color
) IFCOLORX(&& mline_old
.colorx
)))
523 MakeBlankLine(blank
, maxwidth
);
524 bzero((char *)null
, maxwidth
);
526 mline_blank
.image
= blank
;
527 mline_blank
.attr
= null
;
528 mline_null
.image
= null
;
529 mline_null
.attr
= null
;
531 mline_blank
.font
= null
;
532 mline_null
.font
= null
;
535 mline_blank
.color
= null
;
536 mline_null
.color
= null
;
538 mline_blank
.colorx
= null
;
539 mline_null
.colorx
= null
;
543 /* We have to run through all windows to substitute
544 * the null references.
546 for (p
= windows
; p
; p
= p
->w_next
)
549 for (i
= 0; i
< p
->w_height
; i
++, ml
++)
551 if (ml
->attr
== oldnull
)
554 if (ml
->font
== oldnull
)
558 if (ml
->color
== oldnull
)
561 if (ml
->colorx
== oldnull
)
568 for (i
= 0; i
< p
->w_histheight
; i
++, ml
++)
570 if (ml
->attr
== oldnull
)
573 if (ml
->font
== oldnull
)
577 if (ml
->color
== oldnull
)
580 if (ml
->colorx
== oldnull
)
599 if ((nmem
= realloc(mem
, len
)))
607 register unsigned char *p
;
619 #define OLDWIN(y) ((y < p->w_histheight) \
620 ? &p->w_hlines[(p->w_histidx + y) % p->w_histheight] \
621 : &p->w_mlines[y - p->w_histheight])
623 #define NEWWIN(y) ((y < hi) ? &nhlines[y] : &nmlines[y - hi])
627 #define OLDWIN(y) (&p->w_mlines[y])
628 #define NEWWIN(y) (&nmlines[y])
634 ChangeWindowSize(p
, wi
, he
, hi
)
638 struct mline
*mlf
= 0, *mlt
= 0, *ml
, *nmlines
, *nhlines
;
639 int fy
, ty
, l
, lx
, lf
, lt
, yy
, oty
, addone
;
640 int ncx
, ncy
, naka
, t
;
646 if (p
->w_type
== W_TYPE_GROUP
)
648 if (p
->w_width
== wi
&& p
->w_height
== he
&& p
->w_histheight
== hi
)
650 debug("ChangeWindowSize: No change.\n");
658 /* just in case ... */
659 if (wi
&& (p
->w_width
!= wi
|| p
->w_height
!= he
) && p
->w_lay
!= &p
->w_winlay
)
661 debug("ChangeWindowSize: No resize because of overlay?\n");
666 debug("ChangeWindowSize");
667 debug3(" from (%d,%d)+%d", p
->w_width
, p
->w_height
, p
->w_histheight
);
668 debug3(" to(%d,%d)+%d\n", wi
, he
, hi
);
670 fy
= p
->w_histheight
+ p
->w_height
- 1;
673 nmlines
= nhlines
= 0;
680 if (wi
!= p
->w_width
|| he
!= p
->w_height
)
682 if ((nmlines
= (struct mline
*)calloc(he
, sizeof(struct mline
))) == 0)
691 debug1("image stays the same: %d lines\n", he
);
692 nmlines
= p
->w_mlines
;
703 if ((nhlines
= (struct mline
*)calloc(hi
, sizeof(struct mline
))) == 0)
705 Msg(0, "No memory for history buffer - turned off");
712 /* special case: cursor is at magic margin position */
714 if (p
->w_width
&& p
->w_x
== p
->w_width
)
716 debug2("Special addone case: %d %d\n", p
->w_x
, p
->w_y
);
721 /* handle the cursor and autoaka lines now if the widths are equal */
722 if (p
->w_width
== wi
)
724 ncx
= p
->w_x
+ addone
;
725 ncy
= p
->w_y
+ he
- p
->w_height
;
726 /* never lose sight of the line with the cursor on it */
728 for (yy
= p
->w_y
+ p
->w_histheight
- 1; yy
>= 0 && ncy
+ shift
< he
; yy
--)
731 if (ml
->image
[p
->w_width
] == ' ')
738 debug1("resize: cursor out of bounds, shifting %d\n", shift
);
740 if (p
->w_autoaka
> 0)
742 naka
= p
->w_autoaka
+ he
- p
->w_height
+ shift
;
743 if (naka
< 1 || naka
> he
)
753 debug2("fy %d ty %d\n", fy
, ty
);
759 while (fy
>= 0 && ty
>= 0)
761 if (p
->w_width
== wi
)
763 /* here is a simple shortcut: just copy over */
773 /* calculate lenght */
774 for (l
= p
->w_width
- 1; l
> 0; l
--)
775 if (mlf
->image
[l
] != ' ' || mlf
->attr
[l
])
777 if (fy
== p
->w_y
+ p
->w_histheight
&& l
< p
->w_x
)
778 l
= p
->w_x
; /* cursor is non blank */
782 /* add wrapped lines to length */
783 for (yy
= fy
- 1; yy
>= 0; yy
--)
786 if (ml
->image
[p
->w_width
] == ' ')
792 lt
= (l
- 1) % wi
+ 1; /* lf is set above */
794 while (l
> 0 && fy
>= 0 && ty
>= 0)
796 lx
= lt
> lf
? lf
: lt
;
799 if (AllocMline(mlt
, wi
+ 1))
801 MakeBlankLine(mlt
->image
+ lt
, wi
- lt
);
802 mlt
->image
[wi
] = ((oty
== ty
) ? ' ' : 0);
804 if (BcopyMline(mlf
, lf
- lx
, mlt
, lt
- lx
, lx
, wi
+ 1))
807 /* did we copy the cursor ? */
808 if (fy
== p
->w_y
+ p
->w_histheight
&& lf
- lx
<= p
->w_x
&& lf
> p
->w_x
)
810 ncx
= p
->w_x
+ lt
- lf
+ addone
;
812 shift
= wi
? -ncy
+ (l
- lx
) / wi
: 0;
813 if (ty
+ shift
> hi
+ he
- 1)
814 shift
= hi
+ he
- 1 - ty
;
817 debug3("resize: cursor out of bounds, shifting %d [%d/%d]\n", shift
, lt
- lx
, wi
);
818 for (y
= hi
+ he
- 1; y
>= ty
; y
--)
824 ml
= NEWWIN(y
- shift
);
832 naka
= naka
+ shift
> he
? 0 : naka
+ shift
;
836 /* did we copy autoaka line ? */
837 if (p
->w_autoaka
> 0 && fy
== p
->w_autoaka
- 1 + p
->w_histheight
&& lf
- lx
<= 0)
838 naka
= ty
- hi
>= 0 ? 1 + ty
- hi
: 0;
857 ASSERT(l
!= 0 || fy
== yy
);
867 if (AllocMline(mlt
, wi
+ 1))
869 MakeBlankLine(mlt
->image
, wi
+ 1);
875 if (nmlines
!= p
->w_mlines
)
876 for (fy
= 0; fy
< p
->w_height
+ p
->w_histheight
; fy
++)
879 ASSERT(ml
->image
== 0);
883 if (p
->w_mlines
&& p
->w_mlines
!= nmlines
)
884 free((char *)p
->w_mlines
);
885 p
->w_mlines
= nmlines
;
887 if (p
->w_hlines
&& p
->w_hlines
!= nhlines
)
888 free((char *)p
->w_hlines
);
889 p
->w_hlines
= nhlines
;
891 nmlines
= nhlines
= 0;
894 if (p
->w_width
!= wi
)
898 t
= p
->w_tabs
? p
->w_width
: 0;
899 p
->w_tabs
= xrealloc(p
->w_tabs
, wi
+ 1);
905 for (ty
= he
+ hi
- 1; ty
>= 0; ty
--)
910 if (nmlines
&& p
->w_mlines
!= nmlines
)
911 free((char *)nmlines
);
913 if (nhlines
&& p
->w_hlines
!= nhlines
)
914 free((char *)nhlines
);
922 p
->w_tabs
[t
] = t
&& !(t
& 7) ? 1 : 0;
933 /* Change w_Saved_y - this is only an estimate... */
934 p
->w_Saved_y
+= ncy
- p
->w_y
;
938 if (p
->w_autoaka
> 0)
941 /* do sanity checks */
946 if (p
->w_Saved_x
> wi
)
948 if (p
->w_Saved_y
< 0)
950 if (p
->w_Saved_y
>= he
)
951 p
->w_Saved_y
= he
- 1;
953 /* reset scrolling region */
957 /* signal new size to window */
959 if (wi
&& (p
->w_width
!= wi
|| p
->w_height
!= he
)
960 && p
->w_width
!= 0 && p
->w_height
!= 0 && p
->w_ptyfd
>= 0 && p
->w_pid
)
964 debug("Setting pty winsize.\n");
965 if (ioctl(p
->w_ptyfd
, TIOCSWINSZ
, (char *)&glwz
))
966 debug2("SetPtySize: errno %d (fd:%d)\n", errno
, p
->w_ptyfd
);
968 #endif /* TIOCSWINSZ */
975 p
->w_histheight
= hi
;
978 #ifdef BUILTIN_TELNET
979 if (p
->w_type
== W_TYPE_TELNET
)
984 /* Test if everything was ok */
985 for (fy
= 0; fy
< p
->w_height
+ p
->w_histheight
; fy
++)
990 if (p
->w_encoding
== UTF8
)
992 for (l
= 0; l
< p
->w_width
; l
++)
993 ASSERT(ml
->image
[l
] >= ' ' || ml
->font
[l
]);
997 for (l
= 0; l
< p
->w_width
; l
++)
998 ASSERT(ml
->image
[l
] >= ' ');
1010 if (p
->w_alt_mlines
)
1012 for (i
= 0; i
< p
->w_alt_height
; i
++)
1013 FreeMline(p
->w_alt_mlines
+ i
);
1014 free(p
->w_alt_mlines
);
1016 p
->w_alt_mlines
= 0;
1018 p
->w_alt_height
= 0;
1022 if (p
->w_alt_hlines
)
1024 for (i
= 0; i
< p
->w_alt_histheight
; i
++)
1025 FreeMline(p
->w_alt_hlines
+ i
);
1026 free(p
->w_alt_hlines
);
1028 p
->w_alt_hlines
= 0;
1029 p
->w_alt_histidx
= 0;
1031 p
->w_alt_histheight
= 0;
1041 ml
= p
->w_alt_mlines
; p
->w_alt_mlines
= p
->w_mlines
; p
->w_mlines
= ml
;
1042 t
= p
->w_alt_width
; p
->w_alt_width
= p
->w_width
; p
->w_width
= t
;
1043 t
= p
->w_alt_height
; p
->w_alt_height
= p
->w_height
; p
->w_height
= t
;
1044 t
= p
->w_alt_histheight
; p
->w_alt_histheight
= p
->w_histheight
; p
->w_histheight
= t
;
1045 t
= p
->w_alt_x
; p
->w_alt_x
= p
->w_x
; p
->w_x
= t
;
1046 t
= p
->w_alt_y
; p
->w_alt_y
= p
->w_y
; p
->w_y
= t
;
1048 ml
= p
->w_alt_hlines
; p
->w_alt_hlines
= p
->w_hlines
; p
->w_hlines
= ml
;
1049 t
= p
->w_alt_histidx
; p
->w_alt_histidx
= p
->w_histidx
; p
->w_histidx
= t
;
1057 int ox
= p
->w_x
, oy
= p
->w_y
;
1060 ChangeWindowSize(p
, p
->w_alt_width
, p
->w_alt_height
, p
->w_alt_histheight
);
1069 if (!p
->w_alt_mlines
)
1072 ChangeWindowSize(p
, p
->w_alt_width
, p
->w_alt_height
, p
->w_alt_histheight
);