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
)
149 struct canvas
*cv
, **cvpp
;
151 int y
, h
, hn
, xe
, ye
;
153 debug2("ChangeScreenSize from (%d,%d) ", D_width
, D_height
);
154 debug3("to (%d,%d) (change_fore: %d)\n",wi
, he
, change_fore
);
158 cv
->c_ye
= he
- 1 - ((cv
->c_slperp
&& cv
->c_slperp
->c_slnext
) || captionalways
) - (D_has_hstatus
== HSTATUS_LASTLINE
);
162 RecreateCanvasChain();
163 RethinkDisplayViewports();
168 D_fore
= Layer2Window(D_forecv
->c_layer
);
181 if (D_CZ0
&& (wi
== Z0width
|| wi
== Z1width
) &&
182 (D_CO
== Z0width
|| D_CO
== Z1width
))
188 debug2("Default size: (%d,%d)\n", D_defwidth
, D_defheight
);
190 ResizeLayersToCanvases();
191 if (D_CWS
== NULL
&& displays
->d_next
== 0)
193 /* adapt all windows - to be removed ? */
194 for (p
= windows
; p
; p
= p
->w_next
)
196 debug1("Trying to change window %d.\n", p
->w_number
);
199 if (D_CZ0
&& p
->w_width
!= wi
&& (wi
== Z0width
|| wi
== Z1width
))
201 if (p
->w_width
> (Z0width
+ Z1width
) / 2)
207 if (p
->w_savelayer
&& p
->w_savelayer
->l_cvlist
== 0)
208 ResizeLayer(p
->w_savelayer
, wwi
, he
, 0);
210 ChangeWindowSize(p
, wwi
, he
, p
->w_histheight
);
217 ResizeLayersToCanvases()
223 debug("ResizeLayersToCanvases\n");
225 for (cv
= D_cvlist
; cv
; cv
= cv
->c_next
)
230 debug("Doing canvas: ");
231 if (l
->l_width
== cv
->c_xe
- cv
->c_xs
+ 1 &&
232 l
->l_height
== cv
->c_ye
- cv
->c_ys
+ 1)
234 debug("already fitting.\n");
237 if (!MayResizeLayer(l
))
239 debug("may not resize.\n");
243 debug("doing resize.\n");
244 ResizeLayer(l
, cv
->c_xe
- cv
->c_xs
+ 1, cv
->c_ye
- cv
->c_ys
+ 1, display
);
247 /* normalize window, see screen.c */
248 lx
= cv
->c_layer
->l_x
;
249 ly
= cv
->c_layer
->l_y
;
250 if (ly
+ cv
->c_yoff
< cv
->c_ys
)
252 cv
->c_yoff
= cv
->c_ys
- ly
;
253 RethinkViewportOffsets(cv
);
255 else if (ly
+ cv
->c_yoff
> cv
->c_ye
)
257 cv
->c_yoff
= cv
->c_ye
- ly
;
258 RethinkViewportOffsets(cv
);
260 if (lx
+ cv
->c_xoff
< cv
->c_xs
)
262 int n
= cv
->c_xs
- (lx
+ cv
->c_xoff
);
263 if (n
< (cv
->c_xe
- cv
->c_xs
+ 1) / 2)
264 n
= (cv
->c_xe
- cv
->c_xs
+ 1) / 2;
265 if (cv
->c_xoff
+ n
> cv
->c_xs
)
266 n
= cv
->c_xs
- cv
->c_xoff
;
268 RethinkViewportOffsets(cv
);
270 else if (lx
+ cv
->c_xoff
> cv
->c_xe
)
272 int n
= lx
+ cv
->c_xoff
- cv
->c_xe
;
273 if (n
< (cv
->c_xe
- cv
->c_xs
+ 1) / 2)
274 n
= (cv
->c_xe
- cv
->c_xs
+ 1) / 2;
275 if (cv
->c_xoff
- n
+ cv
->c_layer
->l_width
- 1 < cv
->c_xe
)
276 n
= cv
->c_xoff
+ cv
->c_layer
->l_width
- 1 - cv
->c_xe
;
278 RethinkViewportOffsets(cv
);
294 debug("MayResizeLayer:\n");
295 for (; l
; l
= l
->l_next
)
298 if (++cvs
> 1 || l
->l_cvlist
->c_lnext
)
300 debug1("may not - cvs %d\n", cvs
);
304 debug("may resize\n");
309 * Easy implementation: rely on the fact that the only layers
310 * supporting resize are Win and Blank. So just kill all overlays.
312 * This is a lot harder if done the right way...
318 Msg(0, "Aborted because of window size change.");
322 ResizeLayer(l
, wi
, he
, norefdisp
)
325 struct display
*norefdisp
;
329 struct layer
*oldflayer
= flayer
;
330 struct display
*d
, *olddisplay
= display
;
332 if (l
->l_width
== wi
&& l
->l_height
== he
)
336 if (oldflayer
&& (l
== oldflayer
|| Layer2Window(oldflayer
) == p
))
337 while (oldflayer
->l_next
)
338 oldflayer
= oldflayer
->l_next
;
342 for (d
= displays
; d
; d
= d
->d_next
)
343 for (cv
= d
->d_cvlist
; cv
; cv
= cv
->c_next
)
345 if (p
== Layer2Window(cv
->c_layer
))
347 flayer
= cv
->c_layer
;
350 while (flayer
->l_next
)
357 if (p
== 0 && flayer
->l_next
&& flayer
->l_next
->l_next
== 0 && LayResize(wi
, he
) == 0)
359 flayer
= flayer
->l_next
;
366 for (cv
= flayer
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
367 cv
->c_display
->d_kaablamm
= 1;
368 while (flayer
->l_next
)
372 flayer
= &p
->w_layer
;
374 /* now everybody is on flayer, redisplay */
376 for (display
= displays
; display
; display
= display
->d_next
)
378 if (display
== norefdisp
)
380 for (cv
= D_cvlist
; cv
; cv
= cv
->c_next
)
381 if (cv
->c_layer
== l
)
383 CV_CALL(cv
, LayRedisplayLine(-1, -1, -1, 0));
384 RefreshArea(cv
->c_xs
, cv
->c_ys
, cv
->c_xe
, cv
->c_ye
, 0);
393 display
= olddisplay
;
403 if (ml
->attr
&& ml
->attr
!= null
)
406 if (ml
->font
&& ml
->font
!= null
)
410 if (ml
->color
&& ml
->color
!= null
)
413 if (ml
->colorx
&& ml
->colorx
!= null
)
425 ml
->image
= malloc(w
);
443 BcopyMline(mlf
, xf
, mlt
, xt
, l
, w
)
444 struct mline
*mlf
, *mlt
;
449 bcopy((char *)mlf
->image
+ xf
, (char *)mlt
->image
+ xt
, l
);
450 if (mlf
->attr
!= null
&& mlt
->attr
== null
)
452 if ((mlt
->attr
= (unsigned char *)malloc(w
)) == 0)
453 mlt
->attr
= null
, r
= -1;
454 bzero((char *)mlt
->attr
, w
);
456 if (mlt
->attr
!= null
)
457 bcopy((char *)mlf
->attr
+ xf
, (char *)mlt
->attr
+ xt
, l
);
459 if (mlf
->font
!= null
&& mlt
->font
== null
)
461 if ((mlt
->font
= (unsigned char *)malloc(w
)) == 0)
462 mlt
->font
= null
, r
= -1;
463 bzero((char *)mlt
->font
, w
);
465 if (mlt
->font
!= null
)
466 bcopy((char *)mlf
->font
+ xf
, (char *)mlt
->font
+ xt
, l
);
469 if (mlf
->color
!= null
&& mlt
->color
== null
)
471 if ((mlt
->color
= (unsigned char *)malloc(w
)) == 0)
472 mlt
->color
= null
, r
= -1;
473 bzero((char *)mlt
->color
, w
);
475 if (mlt
->color
!= null
)
476 bcopy((char *)mlf
->color
+ xf
, (char *)mlt
->color
+ xt
, l
);
478 if (mlf
->colorx
!= null
&& mlt
->colorx
== null
)
480 if ((mlt
->colorx
= (unsigned char *)malloc(w
)) == 0)
481 mlt
->colorx
= null
, r
= -1;
482 bzero((char *)mlt
->colorx
, w
);
484 if (mlt
->colorx
!= null
)
485 bcopy((char *)mlf
->colorx
+ xf
, (char *)mlt
->colorx
+ xt
, l
);
498 unsigned char *oldnull
= null
;
503 wi
= ((wi
+ 1) + 255) & ~255;
507 debug1("New maxwidth: %d\n", maxwidth
);
508 blank
= (unsigned char *)xrealloc((char *)blank
, maxwidth
);
509 null
= (unsigned char *)xrealloc((char *)null
, maxwidth
);
510 mline_old
.image
= (unsigned char *)xrealloc((char *)mline_old
.image
, maxwidth
);
511 mline_old
.attr
= (unsigned char *)xrealloc((char *)mline_old
.attr
, maxwidth
);
513 mline_old
.font
= (unsigned char *)xrealloc((char *)mline_old
.font
, maxwidth
);
516 mline_old
.color
= (unsigned char *)xrealloc((char *)mline_old
.color
, maxwidth
);
518 mline_old
.colorx
= (unsigned char *)xrealloc((char *)mline_old
.color
, maxwidth
);
521 if (!(blank
&& null
&& mline_old
.image
&& mline_old
.attr
IFFONT(&& mline_old
.font
) IFCOLOR(&& mline_old
.color
) IFCOLORX(&& mline_old
.colorx
)))
524 MakeBlankLine(blank
, maxwidth
);
525 bzero((char *)null
, maxwidth
);
527 mline_blank
.image
= blank
;
528 mline_blank
.attr
= null
;
529 mline_null
.image
= null
;
530 mline_null
.attr
= null
;
532 mline_blank
.font
= null
;
533 mline_null
.font
= null
;
536 mline_blank
.color
= null
;
537 mline_null
.color
= null
;
539 mline_blank
.colorx
= null
;
540 mline_null
.colorx
= null
;
544 /* We have to run through all windows to substitute
545 * the null references.
547 for (p
= windows
; p
; p
= p
->w_next
)
550 for (i
= 0; i
< p
->w_height
; i
++, ml
++)
552 if (ml
->attr
== oldnull
)
555 if (ml
->font
== oldnull
)
559 if (ml
->color
== oldnull
)
562 if (ml
->colorx
== oldnull
)
569 for (i
= 0; i
< p
->w_histheight
; i
++, ml
++)
571 if (ml
->attr
== oldnull
)
574 if (ml
->font
== oldnull
)
578 if (ml
->color
== oldnull
)
581 if (ml
->colorx
== oldnull
)
600 if ((nmem
= realloc(mem
, len
)))
608 register unsigned char *p
;
620 #define OLDWIN(y) ((y < p->w_histheight) \
621 ? &p->w_hlines[(p->w_histidx + y) % p->w_histheight] \
622 : &p->w_mlines[y - p->w_histheight])
624 #define NEWWIN(y) ((y < hi) ? &nhlines[y] : &nmlines[y - hi])
628 #define OLDWIN(y) (&p->w_mlines[y])
629 #define NEWWIN(y) (&nmlines[y])
635 ChangeWindowSize(p
, wi
, he
, hi
)
639 struct mline
*mlf
= 0, *mlt
= 0, *ml
, *nmlines
, *nhlines
;
640 int fy
, ty
, l
, lx
, lf
, lt
, yy
, oty
, addone
;
641 int ncx
, ncy
, naka
, t
;
647 if (p
->w_type
== W_TYPE_GROUP
)
649 if (p
->w_width
== wi
&& p
->w_height
== he
&& p
->w_histheight
== hi
)
651 debug("ChangeWindowSize: No change.\n");
659 /* just in case ... */
660 if (wi
&& (p
->w_width
!= wi
|| p
->w_height
!= he
) && p
->w_lay
!= &p
->w_winlay
)
662 debug("ChangeWindowSize: No resize because of overlay?\n");
667 debug("ChangeWindowSize");
668 debug3(" from (%d,%d)+%d", p
->w_width
, p
->w_height
, p
->w_histheight
);
669 debug3(" to(%d,%d)+%d\n", wi
, he
, hi
);
671 fy
= p
->w_histheight
+ p
->w_height
- 1;
674 nmlines
= nhlines
= 0;
681 if (wi
!= p
->w_width
|| he
!= p
->w_height
)
683 if ((nmlines
= (struct mline
*)calloc(he
, sizeof(struct mline
))) == 0)
692 debug1("image stays the same: %d lines\n", he
);
693 nmlines
= p
->w_mlines
;
704 if ((nhlines
= (struct mline
*)calloc(hi
, sizeof(struct mline
))) == 0)
706 Msg(0, "No memory for history buffer - turned off");
713 /* special case: cursor is at magic margin position */
715 if (p
->w_width
&& p
->w_x
== p
->w_width
)
717 debug2("Special addone case: %d %d\n", p
->w_x
, p
->w_y
);
722 /* handle the cursor and autoaka lines now if the widths are equal */
723 if (p
->w_width
== wi
)
725 ncx
= p
->w_x
+ addone
;
726 ncy
= p
->w_y
+ he
- p
->w_height
;
727 /* never lose sight of the line with the cursor on it */
729 for (yy
= p
->w_y
+ p
->w_histheight
- 1; yy
>= 0 && ncy
+ shift
< he
; yy
--)
732 if (ml
->image
[p
->w_width
] == ' ')
739 debug1("resize: cursor out of bounds, shifting %d\n", shift
);
741 if (p
->w_autoaka
> 0)
743 naka
= p
->w_autoaka
+ he
- p
->w_height
+ shift
;
744 if (naka
< 1 || naka
> he
)
754 debug2("fy %d ty %d\n", fy
, ty
);
760 while (fy
>= 0 && ty
>= 0)
762 if (p
->w_width
== wi
)
764 /* here is a simple shortcut: just copy over */
774 /* calculate lenght */
775 for (l
= p
->w_width
- 1; l
> 0; l
--)
776 if (mlf
->image
[l
] != ' ' || mlf
->attr
[l
])
778 if (fy
== p
->w_y
+ p
->w_histheight
&& l
< p
->w_x
)
779 l
= p
->w_x
; /* cursor is non blank */
783 /* add wrapped lines to length */
784 for (yy
= fy
- 1; yy
>= 0; yy
--)
787 if (ml
->image
[p
->w_width
] == ' ')
793 lt
= (l
- 1) % wi
+ 1; /* lf is set above */
795 while (l
> 0 && fy
>= 0 && ty
>= 0)
797 lx
= lt
> lf
? lf
: lt
;
800 if (AllocMline(mlt
, wi
+ 1))
802 MakeBlankLine(mlt
->image
+ lt
, wi
- lt
);
803 mlt
->image
[wi
] = ((oty
== ty
) ? ' ' : 0);
805 if (BcopyMline(mlf
, lf
- lx
, mlt
, lt
- lx
, lx
, wi
+ 1))
808 /* did we copy the cursor ? */
809 if (fy
== p
->w_y
+ p
->w_histheight
&& lf
- lx
<= p
->w_x
&& lf
> p
->w_x
)
811 ncx
= p
->w_x
+ lt
- lf
+ addone
;
813 shift
= wi
? -ncy
+ (l
- lx
) / wi
: 0;
814 if (ty
+ shift
> hi
+ he
- 1)
815 shift
= hi
+ he
- 1 - ty
;
818 debug3("resize: cursor out of bounds, shifting %d [%d/%d]\n", shift
, lt
- lx
, wi
);
819 for (y
= hi
+ he
- 1; y
>= ty
; y
--)
825 ml
= NEWWIN(y
- shift
);
833 naka
= naka
+ shift
> he
? 0 : naka
+ shift
;
837 /* did we copy autoaka line ? */
838 if (p
->w_autoaka
> 0 && fy
== p
->w_autoaka
- 1 + p
->w_histheight
&& lf
- lx
<= 0)
839 naka
= ty
- hi
>= 0 ? 1 + ty
- hi
: 0;
858 ASSERT(l
!= 0 || fy
== yy
);
868 if (AllocMline(mlt
, wi
+ 1))
870 MakeBlankLine(mlt
->image
, wi
+ 1);
876 if (nmlines
!= p
->w_mlines
)
877 for (fy
= 0; fy
< p
->w_height
+ p
->w_histheight
; fy
++)
880 ASSERT(ml
->image
== 0);
884 if (p
->w_mlines
&& p
->w_mlines
!= nmlines
)
885 free((char *)p
->w_mlines
);
886 p
->w_mlines
= nmlines
;
888 if (p
->w_hlines
&& p
->w_hlines
!= nhlines
)
889 free((char *)p
->w_hlines
);
890 p
->w_hlines
= nhlines
;
892 nmlines
= nhlines
= 0;
895 if (p
->w_width
!= wi
)
899 t
= p
->w_tabs
? p
->w_width
: 0;
900 p
->w_tabs
= xrealloc(p
->w_tabs
, wi
+ 1);
906 for (ty
= he
+ hi
- 1; ty
>= 0; ty
--)
911 if (nmlines
&& p
->w_mlines
!= nmlines
)
912 free((char *)nmlines
);
914 if (nhlines
&& p
->w_hlines
!= nhlines
)
915 free((char *)nhlines
);
923 p
->w_tabs
[t
] = t
&& !(t
& 7) ? 1 : 0;
934 /* Change w_Saved_y - this is only an estimate... */
935 p
->w_Saved_y
+= ncy
- p
->w_y
;
939 if (p
->w_autoaka
> 0)
942 /* do sanity checks */
947 if (p
->w_Saved_x
> wi
)
949 if (p
->w_Saved_y
< 0)
951 if (p
->w_Saved_y
>= he
)
952 p
->w_Saved_y
= he
- 1;
954 /* reset scrolling region */
958 /* signal new size to window */
960 if (wi
&& (p
->w_width
!= wi
|| p
->w_height
!= he
) && 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
);