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