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 "config.h"
30 #include "screen.h"
31 #include "extern.h"
32 #include "canvas.h"
33 #include "list_generic.h"
34 
35 extern struct display *display;
36 extern struct win *fore, *windows;
37 extern struct layer *flayer;
38 extern int captionalways;
39 extern struct LayFuncs BlankLf;
40 extern int focusminwidth, focusminheight;
41 
42 static void
CanvasInitBlank(cv)43 CanvasInitBlank(cv)
44 struct canvas *cv;
45 {
46   cv->c_blank.l_cvlist = cv;
47   cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
48   cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
49   cv->c_blank.l_x = cv->c_blank.l_y = 0;
50   cv->c_blank.l_layfn = &BlankLf;
51   cv->c_blank.l_data = 0;
52   cv->c_blank.l_next = 0;
53   cv->c_blank.l_bottom = &cv->c_blank;
54   cv->c_blank.l_blocking = 0;
55   cv->c_layer = &cv->c_blank;
56 }
57 
58 static void
FreePerp(pcv)59 FreePerp(pcv)
60 struct canvas *pcv;
61 {
62   struct canvas *cv;
63 
64   if (!pcv->c_slperp)
65     return;
66   cv = pcv->c_slperp;
67   cv->c_slprev = pcv->c_slprev;
68   if (cv->c_slprev)
69     cv->c_slprev->c_slnext = cv;
70   cv->c_slback = pcv->c_slback;
71   if (cv->c_slback && cv->c_slback->c_slperp == pcv)
72     cv->c_slback->c_slperp = cv;
73   cv->c_slorient = pcv->c_slorient;
74   cv->c_slweight = pcv->c_slweight;
75   while (cv->c_slnext)
76     {
77       cv = cv->c_slnext;
78       cv->c_slorient = pcv->c_slorient;
79       cv->c_slback = pcv->c_slback;
80       cv->c_slweight = pcv->c_slweight;
81     }
82   cv->c_slnext = pcv->c_slnext;
83   if (cv->c_slnext)
84     cv->c_slnext->c_slprev = cv;
85   LayerCleanupMemory(&pcv->c_blank);
86   free(pcv);
87 }
88 
89 void
FreeCanvas(cv)90 FreeCanvas(cv)
91 struct canvas *cv;
92 {
93   struct viewport *vp, *nvp;
94   struct canvas **cvp;
95   struct win *p;
96 
97   if (cv->c_slprev)
98     cv->c_slprev->c_slnext = cv->c_slnext;
99   if (cv->c_slnext)
100     cv->c_slnext->c_slprev = cv->c_slprev;
101   if (cv->c_slback && cv->c_slback->c_slperp == cv)
102     cv->c_slback->c_slperp = cv->c_slnext ? cv->c_slnext : cv->c_slprev;
103   if (cv->c_slperp)
104     {
105       while (cv->c_slperp)
106 	FreeCanvas(cv->c_slperp);
107       LayerCleanupMemory(&cv->c_blank);
108       free(cv);
109       return;
110     }
111 
112   if (display)
113     {
114       if (D_forecv == cv)
115 	D_forecv = 0;
116       /* remove from canvas chain as SetCanvasWindow might call
117        * some layer function */
118       for (cvp = &D_cvlist; *cvp ; cvp = &(*cvp)->c_next)
119 	if (*cvp == cv)
120 	  {
121 	    *cvp = cv->c_next;
122 	    break;
123 	  }
124     }
125   p = cv->c_layer ? Layer2Window(cv->c_layer) : 0;
126   SetCanvasWindow(cv, 0);
127   if (p)
128     WindowChanged(p, 'u');
129   if (flayer == cv->c_layer)
130     flayer = 0;
131   for (vp = cv->c_vplist; vp; vp = nvp)
132     {
133       vp->v_canvas = 0;
134       nvp = vp->v_next;
135       vp->v_next = 0;
136       free(vp);
137     }
138   evdeq(&cv->c_captev);
139   LayerCleanupMemory(&cv->c_blank);
140   free(cv);
141 }
142 
143 int
CountCanvas(cv)144 CountCanvas(cv)
145 struct canvas *cv;
146 {
147   int num = 0;
148   for (; cv; cv = cv->c_slnext)
149     {
150       if (cv->c_slperp)
151 	{
152 	  struct canvas *cvp;
153 	  int nump = 1, n;
154           for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
155 	    if (cvp->c_slperp)
156 	      {
157 		n = CountCanvas(cvp->c_slperp);
158 		if (n > nump)
159 		  nump = n;
160 	      }
161 	  num += nump;
162 	}
163       else
164 	num++;
165     }
166   return num;
167 }
168 
169 int
CountCanvasPerp(cv)170 CountCanvasPerp(cv)
171 struct canvas *cv;
172 {
173   struct canvas *cvp;
174   int num = 1, n;
175   for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
176     if (cvp->c_slperp)
177       {
178 	n = CountCanvas(cvp->c_slperp);
179 	if (n > num)
180 	  num = n;
181       }
182   return num;
183 }
184 
185 struct canvas *
FindCanvas(x,y)186 FindCanvas(x, y)
187 int x, y;
188 {
189   struct canvas *cv, *mcv = 0;
190   int m, mm = 0;
191 
192   for (cv = D_cvlist; cv; cv = cv->c_next)
193     {
194       /* ye + 1 because of caption line */
195       if (x >= cv->c_xs && x <= cv->c_xe && y >= cv->c_ys && y <= cv->c_ye + 1)
196 	return cv;
197       if (cv == D_forecv)
198 	continue;
199       m = 0;
200       if (x >= D_forecv->c_xs && x <= D_forecv->c_xe)
201 	{
202 	  if (x < cv->c_xs || x > cv->c_xe)
203 	    continue;
204           if (y < D_forecv->c_ys && y < cv->c_ys)
205 	    continue;
206           if (y > D_forecv->c_ye + 1 && y > cv->c_ye + 1)
207 	    continue;
208 	  if (y < cv->c_ys)
209 	    m = cv->c_ys - y;
210 	  if (y > cv->c_ye + 1)
211 	    m = y - (cv->c_ye + 1);
212 	}
213       if (y >= D_forecv->c_ys && y <= D_forecv->c_ye + 1)
214 	{
215 	  if (y < cv->c_ys || y > cv->c_ye + 1)
216 	    continue;
217           if (x < D_forecv->c_xs && x < cv->c_xs)
218 	    continue;
219           if (x > D_forecv->c_xe && x > cv->c_xe)
220 	    continue;
221 	  if (x < cv->c_xs)
222 	    m = cv->c_xs - x;
223 	  if (x > cv->c_xe)
224 	    m = x - cv->c_xe;
225 	}
226       if (m && (!mm || m < mm))
227 	{
228 	  mcv = cv;
229 	  mm = m;
230 	}
231     }
232   return mcv ? mcv : D_forecv;
233 }
234 
235 void
SetCanvasWindow(cv,wi)236 SetCanvasWindow(cv, wi)
237 struct canvas *cv;
238 struct win *wi;
239 {
240   struct win *p = 0, **pp;
241   struct layer *l;
242   struct canvas *cvp, **cvpp;
243 
244   l = cv->c_layer;
245   display = cv->c_display;
246 
247   if (l)
248     {
249       /* remove old layer */
250       for (cvpp = &l->l_cvlist; (cvp = *cvpp); cvpp = &cvp->c_lnext)
251 	if (cvp == cv)
252 	  break;
253       ASSERT(cvp);
254       *cvpp = cvp->c_lnext;
255 
256       p = Layer2Window(l);
257       l = cv->c_layer;
258       cv->c_layer = 0;
259 
260       if (p && cv == D_forecv)
261 	{
262 #ifdef MULTIUSER
263 	  ReleaseAutoWritelock(display, p);
264 #endif
265 	  if (p->w_silence)
266 	    {
267 	      SetTimeout(&p->w_silenceev, p->w_silencewait * 1000);
268 	      evenq(&p->w_silenceev);
269 	    }
270 	  D_other = fore;
271 	  D_fore = 0;
272 	}
273       if (l->l_cvlist == 0 && (p == 0 || l != p->w_savelayer))
274 	KillLayerChain(l);
275     }
276 
277   /* find right layer to display on canvas */
278   if (wi && wi->w_type != W_TYPE_GROUP)
279     {
280       l = &wi->w_layer;
281       if (wi->w_savelayer && (wi->w_blocked || wi->w_savelayer->l_cvlist == 0))
282 	l = wi->w_savelayer;
283     }
284   else
285     {
286       l = &cv->c_blank;
287       if (wi)
288 	l->l_data = (char *)wi;
289       else
290 	l->l_data = 0;
291     }
292 
293   /* add our canvas to the layer's canvaslist */
294   ASSERT(l->l_cvlist != cv);
295   cv->c_lnext = l->l_cvlist;
296   l->l_cvlist = cv;
297   cv->c_layer = l;
298   cv->c_xoff = cv->c_xs;
299   cv->c_yoff = cv->c_ys;
300   RethinkViewportOffsets(cv);
301 
302   if (flayer == 0)
303     flayer = l;
304 
305   if (wi && wi->w_type == W_TYPE_GROUP)
306     {
307       /* auto-start windowlist on groups */
308       struct display *d = display;
309       struct layer *oldflayer = flayer;
310       flayer = l;
311       display_windows(0, 0, wi);
312       flayer = oldflayer;
313       display = d;
314     }
315 
316   if (wi && D_other == wi)
317     D_other = wi->w_next;	/* Might be 0, but that's OK. */
318   if (cv == D_forecv)
319     {
320       D_fore = wi;
321       fore = D_fore;	/* XXX ? */
322       if (wi)
323 	{
324 #ifdef MULTIUSER
325 	  ObtainAutoWritelock(display, wi);
326 #endif
327 	  /*
328 	   * Place the window at the head of the most-recently-used list
329 	   */
330 	  if (windows != wi)
331 	    {
332 	      for (pp = &windows; (p = *pp); pp = &p->w_next)
333 		if (p == wi)
334 		  break;
335 	      ASSERT(p);
336 	      *pp = p->w_next;
337 	      p->w_next = windows;
338 	      windows = p;
339 	      WListLinkChanged();
340 	    }
341 	}
342     }
343 }
344 
345 static void
cv_winid_fn(ev,data)346 cv_winid_fn(ev, data)
347 struct event *ev;
348 char *data;
349 {
350   int ox, oy;
351   struct canvas *cv = (struct canvas *)data;
352 
353   display = cv->c_display;
354   if (D_status == STATUS_ON_WIN)
355     {
356       SetTimeout(ev, 1);
357       evenq(ev);
358       return;
359     }
360   ox = D_x;
361   oy = D_y;
362   if (cv->c_ye + 1 < D_height)
363     RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
364   if (ox != -1 && oy != -1)
365     GotoPos(ox, oy);
366 }
367 
368 int
MakeDefaultCanvas()369 MakeDefaultCanvas()
370 {
371   struct canvas *cv;
372 
373   ASSERT(display);
374   if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
375     return -1;
376   cv->c_xs      = 0;
377   cv->c_xe      = D_width - 1;
378   cv->c_ys      = (D_has_hstatus == HSTATUS_FIRSTLINE);
379   cv->c_ye      = D_height - 1 - (D_has_hstatus == HSTATUS_LASTLINE) - captionalways;
380   debug2("MakeDefaultCanvas 0,0 %d,%d\n", cv->c_xe, cv->c_ye);
381   cv->c_xoff    = 0;
382   cv->c_yoff    = 0;
383   cv->c_next = 0;
384   cv->c_display = display;
385   cv->c_vplist = 0;
386   cv->c_slnext = 0;
387   cv->c_slprev = 0;
388   cv->c_slperp = 0;
389   cv->c_slweight = 1;
390   cv->c_slback = &D_canvas;
391   D_canvas.c_slperp = cv;
392   D_canvas.c_xs = cv->c_xs;
393   D_canvas.c_xe = cv->c_xe;
394   D_canvas.c_ys = cv->c_ys;
395   D_canvas.c_ye = cv->c_ye;
396   cv->c_slorient = SLICE_UNKN;
397   cv->c_captev.type = EV_TIMEOUT;
398   cv->c_captev.data = (char *)cv;
399   cv->c_captev.handler = cv_winid_fn;
400 
401   CanvasInitBlank(cv);
402   cv->c_lnext = 0;
403 
404   D_cvlist = cv;
405   RethinkDisplayViewports();
406   D_forecv = cv; 	      /* default input focus */
407   return 0;
408 }
409 
410 static struct canvas **
CreateCanvasChainRec(cv,cvp)411 CreateCanvasChainRec(cv, cvp)
412 struct canvas *cv;
413 struct canvas **cvp;
414 {
415   for (; cv; cv = cv->c_slnext)
416     {
417       if (cv->c_slperp)
418 	cvp = CreateCanvasChainRec(cv->c_slperp, cvp);
419       else
420 	{
421 	  *cvp = cv;
422 	  cvp = &cv->c_next;
423 	}
424     }
425   return cvp;
426 }
427 
428 void
RecreateCanvasChain()429 RecreateCanvasChain()
430 {
431   struct canvas **cvp;
432   cvp = CreateCanvasChainRec(D_canvas.c_slperp, &D_cvlist);
433   *cvp = 0;
434 }
435 
436 void
EqualizeCanvas(cv,gflag)437 EqualizeCanvas(cv, gflag)
438 struct canvas *cv;
439 int gflag;
440 {
441   struct canvas *cv2;
442   for (; cv; cv = cv->c_slnext)
443     {
444       if (cv->c_slperp && gflag)
445 	{
446 	  cv->c_slweight = CountCanvasPerp(cv);
447 	  for (cv2 = cv->c_slperp; cv2; cv2 = cv2->c_slnext)
448 	    if (cv2->c_slperp)
449 	      EqualizeCanvas(cv2->c_slperp, gflag);
450 	}
451       else
452 	cv->c_slweight = 1;
453     }
454 }
455 
456 void
ResizeCanvas(cv)457 ResizeCanvas(cv)
458 struct canvas *cv;
459 {
460   struct canvas *cv2, *cvn, *fcv;
461   int nh, i, maxi, hh, m, w, wsum;
462   int need, got;
463   int xs, ys, xe, ye;
464   int focusmin = 0;
465 
466   xs = cv->c_xs;
467   ys = cv->c_ys;
468   xe = cv->c_xe;
469   ye = cv->c_ye;
470   cv = cv->c_slperp;
471   debug2("ResizeCanvas: %d,%d", xs, ys);
472   debug2(" %d,%d\n", xe, ye);
473   if (cv == 0)
474     return;
475   if (cv->c_slorient == SLICE_UNKN)
476     {
477       ASSERT(!cv->c_slnext && !cv->c_slperp);
478       cv->c_xs = xs;
479       cv->c_xe = xe;
480       cv->c_ys = ys;
481       cv->c_ye = ye;
482       cv->c_xoff = cv->c_xs;
483       cv->c_yoff = cv->c_ys;
484       cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
485       cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
486       return;
487     }
488 
489   fcv = 0;
490   if (focusminwidth || focusminheight)
491     {
492       debug("searching for focus canvas\n");
493       cv2 = D_forecv;
494       while (cv2->c_slback)
495         {
496 	  if (cv2->c_slback == cv->c_slback)
497 	    {
498 	      fcv = cv2;
499 	      focusmin = cv->c_slorient == SLICE_VERT ? focusminheight : focusminwidth;
500 	      if (focusmin > 0)
501 		focusmin--;
502 	      else if (focusmin < 0)
503 		focusmin = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
504 	      debug1("found, focusmin=%d\n", focusmin);
505 	    }
506           cv2 = cv2->c_slback;
507         }
508     }
509   if (focusmin)
510     {
511       m = CountCanvas(cv) * 2;
512       nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
513       nh -= m;
514       if (nh < 0)
515 	nh = 0;
516       if (focusmin > nh)
517 	focusmin = nh;
518       debug1("corrected to %d\n", focusmin);
519     }
520 
521   /* pass 1: calculate weight sum */
522   for (cv2 = cv, wsum = 0; cv2; cv2 = cv2->c_slnext)
523     {
524       debug1("  weight %d\n", cv2->c_slweight);
525       wsum += cv2->c_slweight;
526     }
527   debug1("wsum = %d\n", wsum);
528   if (wsum == 0)
529     wsum = 1;
530   w = wsum;
531 
532   /* pass 2: calculate need/excess space */
533   nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
534   for (cv2 = cv, need = got = 0; cv2; cv2 = cv2->c_slnext)
535     {
536       m = cv2->c_slperp ? CountCanvasPerp(cv2) * 2 - 1 : 1;
537       if (cv2 == fcv)
538 	m += focusmin;
539       hh = cv2->c_slweight ? nh * cv2->c_slweight / w : 0;
540       w -= cv2->c_slweight;
541       nh -= hh;
542       debug2("  should %d min %d\n", hh, m);
543       if (hh <= m + 1)
544         need += m + 1 - hh;
545       else
546         got += hh - m - 1;
547     }
548   debug2("need: %d, got %d\n", need, got);
549   if (need > got)
550     need = got;
551 
552   /* pass 3: distribute space */
553   nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
554   i = cv->c_slorient == SLICE_VERT ? ys : xs;
555   maxi = cv->c_slorient == SLICE_VERT ? ye : xe;
556   w = wsum;
557   for (; cv; cv = cvn)
558     {
559       cvn = cv->c_slnext;
560       if (i > maxi)
561 	{
562 	  if (cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slprev->c_slperp && !cv->c_slprev->c_slprev)
563 	    {
564 	      cv->c_slprev->c_slorient = SLICE_UNKN;
565 	      if (!captionalways)
566 		{
567 	          cv->c_slback->c_ye++;
568 		  cv->c_slprev->c_ye++;
569 		}
570 	    }
571 	  SetCanvasWindow(cv, 0);
572 	  FreeCanvas(cv);
573 	  continue;
574 	}
575       m = cv->c_slperp ? CountCanvasPerp(cv) * 2 - 1 : 1;
576       if (cv == fcv)
577 	m += focusmin;
578       hh = cv->c_slweight ? nh * cv->c_slweight / w : 0;
579       w -= cv->c_slweight;
580       nh -= hh;
581       debug2("  should %d min %d\n", hh, m);
582       if (hh <= m + 1)
583 	{
584 	  hh = m + 1;
585 	  debug1(" -> %d\n", hh);
586 	}
587       else
588 	{
589 	  int hx = 1;       //FIXME Division by zero (got) is posible. "hx = 1" is random number here!!!
590     if (got != 0)
591       hx = need * (hh - m - 1) / got;
592     else
593       debug("   got = 0\n");
594 
595 	  debug3(" -> %d - %d = %d\n", hh, hx, hh - hx);
596 	  got -= (hh - m - 1);
597 	  hh -= hx;
598 	  need -= hx;
599           debug2("   now need=%d got=%d\n", need, got);
600 	}
601       ASSERT(hh >= m + 1);
602       /* hh is window size plus pation line */
603       if (i + hh > maxi + 2)
604 	{
605 	  hh = maxi + 2 - i;
606 	  debug1("  not enough space, reducing to %d\n", hh);
607 	}
608       if (i + hh == maxi + 1)
609 	{
610 	  hh++;
611 	  debug("  incrementing as no other canvas will fit\n");
612 	}
613       if (cv->c_slorient == SLICE_VERT)
614         {
615           cv->c_xs = xs;
616           cv->c_xe = xe;
617           cv->c_ys = i;
618           cv->c_ye = i + hh - 2;
619           cv->c_xoff = xs;
620           cv->c_yoff = i;
621         }
622       else
623         {
624           cv->c_xs = i;
625           cv->c_xe = i + hh - 2;
626           cv->c_ys = ys;
627           cv->c_ye = ye;
628           cv->c_xoff = i;
629           cv->c_yoff = ys;
630         }
631       cv->c_xoff = cv->c_xs;
632       cv->c_yoff = cv->c_ys;
633       cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
634       cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
635       if (cv->c_slperp)
636 	{
637           ResizeCanvas(cv);
638 	  if (!cv->c_slperp->c_slnext)
639 	    {
640 	      debug("deleting perp node\n");
641 	      FreePerp(cv->c_slperp);
642 	      FreePerp(cv);
643 	    }
644 	}
645       i += hh;
646     }
647 }
648 
649 static struct canvas *
AddPerp(cv)650 AddPerp(cv)
651 struct canvas *cv;
652 {
653   struct canvas *pcv;
654   debug("Creating new perp node\n");
655 
656   if ((pcv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
657     return 0;
658   pcv->c_next = 0;
659   pcv->c_display = cv->c_display;
660   pcv->c_slnext = cv->c_slnext;
661   pcv->c_slprev = cv->c_slprev;
662   pcv->c_slperp = cv;
663   pcv->c_slback = cv->c_slback;
664   if (cv->c_slback && cv->c_slback->c_slperp == cv)
665     cv->c_slback->c_slperp = pcv;
666   pcv->c_slorient = cv->c_slorient;
667   pcv->c_xoff = 0;
668   pcv->c_yoff = 0;
669   pcv->c_xs = cv->c_xs;
670   pcv->c_xe = cv->c_xe;
671   pcv->c_ys = cv->c_ys;
672   pcv->c_ye = cv->c_ye;
673   if (pcv->c_slnext)
674     pcv->c_slnext->c_slprev = pcv;
675   if (pcv->c_slprev)
676     pcv->c_slprev->c_slnext = pcv;
677   pcv->c_slweight = cv->c_slweight;
678   CanvasInitBlank(pcv);
679   cv->c_slweight = 1;
680   cv->c_slnext = 0;
681   cv->c_slprev = 0;
682   cv->c_slperp = 0;
683   cv->c_slback = pcv;
684   cv->c_slorient = SLICE_UNKN;
685   return pcv;
686 }
687 
688 int
AddCanvas(orient)689 AddCanvas(orient)
690 int orient;
691 {
692   struct canvas *cv;
693   int xs, xe, ys, ye;
694   int h, num;
695 
696   cv = D_forecv;
697   debug2("AddCanvas orient %d, forecv is %d\n", orient, cv->c_slorient);
698 
699   if (cv->c_slorient != SLICE_UNKN && cv->c_slorient != orient)
700     if (!AddPerp(cv))
701       return -1;
702 
703   cv = D_forecv;
704   xs = cv->c_slback->c_xs;
705   xe = cv->c_slback->c_xe;
706   ys = cv->c_slback->c_ys;
707   ye = cv->c_slback->c_ye;
708   if (!captionalways && cv == D_canvas.c_slperp && !cv->c_slnext)
709     ye--;	/* need space for caption */
710   debug2("Adding Canvas to slice %d,%d ", xs, ys);
711   debug2("%d,%d\n", xe, ye);
712 
713   num = CountCanvas(cv->c_slback->c_slperp) + 1;
714   debug1("Num = %d\n", num);
715   if (orient == SLICE_VERT)
716     h = ye - ys + 1;
717   else
718     h = xe - xs + 1;
719 
720   h -= 2 * num - 1;
721   if (h < 0)
722     return -1;		/* can't fit in */
723 
724   if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
725     return -1;
726 
727   D_forecv->c_slback->c_ye = ye;	/* in case we modified it above */
728   D_forecv->c_slorient = orient;	/* in case it was UNKN */
729   cv->c_slnext = D_forecv->c_slnext;
730   cv->c_slprev = D_forecv;
731   D_forecv->c_slnext = cv;
732   if (cv->c_slnext)
733     cv->c_slnext->c_slprev = cv;
734   cv->c_slorient = orient;
735   cv->c_slback = D_forecv->c_slback;
736 
737   cv->c_xs      = xs;
738   cv->c_xe      = xe;
739   cv->c_ys      = ys;
740   cv->c_ye      = ye;
741   cv->c_xoff    = 0;
742   cv->c_yoff    = 0;
743   cv->c_display = display;
744   cv->c_vplist  = 0;
745   cv->c_captev.type = EV_TIMEOUT;
746   cv->c_captev.data = (char *)cv;
747   cv->c_captev.handler = cv_winid_fn;
748 
749   CanvasInitBlank(cv);
750   cv->c_lnext = 0;
751 
752   cv->c_next    = 0;
753 
754   cv = cv->c_slback;
755   EqualizeCanvas(cv->c_slperp, 0);
756   ResizeCanvas(cv);
757   RecreateCanvasChain();
758   RethinkDisplayViewports();
759   ResizeLayersToCanvases();
760   return 0;
761 }
762 
763 void
RemCanvas()764 RemCanvas()
765 {
766   int ye;
767   struct canvas *cv;
768 
769   debug("RemCanvas\n");
770   cv = D_forecv;
771   ye = cv->c_slback->c_ye;
772   if (cv->c_slorient == SLICE_UNKN)
773     return;
774   while (cv->c_slprev)
775     cv = cv->c_slprev;
776   if (!cv->c_slnext)
777     return;
778   if (!cv->c_slnext->c_slnext && cv->c_slback->c_slback)
779     {
780       /* two canvases in slice, kill perp node */
781       cv = D_forecv;
782       debug("deleting perp node\n");
783       FreePerp(cv->c_slprev ? cv->c_slprev : cv->c_slnext);
784       FreePerp(cv->c_slback);
785     }
786   /* free canvas */
787   cv = D_forecv;
788   D_forecv = cv->c_slprev;
789   if (!D_forecv)
790     D_forecv = cv->c_slnext;
791   FreeCanvas(cv);
792 
793   cv = D_forecv;
794   while (D_forecv->c_slperp)
795     D_forecv = D_forecv->c_slperp;
796 
797   /* if only one canvas left, set orient back to unknown */
798   if (!cv->c_slnext && !cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slperp)
799     {
800       cv->c_slorient = SLICE_UNKN;
801       if (!captionalways)
802 	cv->c_slback->c_ye = ++ye;	/* caption line no longer needed */
803     }
804   cv = cv->c_slback;
805   EqualizeCanvas(cv->c_slperp, 0);
806   ResizeCanvas(cv);
807 
808   D_fore = Layer2Window(D_forecv->c_layer);
809   flayer = D_forecv->c_layer;
810 
811   RecreateCanvasChain();
812   RethinkDisplayViewports();
813   ResizeLayersToCanvases();
814 }
815 
816 void
OneCanvas()817 OneCanvas()
818 {
819   struct canvas *cv = D_forecv, *ocv = 0;
820 
821   if (cv->c_slprev)
822     {
823       ocv = cv->c_slprev;
824       cv->c_slprev->c_slnext = cv->c_slnext;
825     }
826   if (cv->c_slnext)
827     {
828       ocv = cv->c_slnext;
829       cv->c_slnext->c_slprev = cv->c_slprev;
830     }
831   if (!ocv)
832     return;
833   if (cv->c_slback && cv->c_slback->c_slperp == cv)
834     cv->c_slback->c_slperp = ocv;
835   cv->c_slorient = SLICE_UNKN;
836   while (D_canvas.c_slperp)
837     FreeCanvas(D_canvas.c_slperp);
838   cv = D_forecv;
839   D_canvas.c_slperp = cv;
840   cv->c_slback = &D_canvas;
841   cv->c_slnext = 0;
842   cv->c_slprev = 0;
843   ASSERT(!cv->c_slperp);
844   if (!captionalways)
845     D_canvas.c_ye++;	/* caption line no longer needed */
846   ResizeCanvas(&D_canvas);
847   RecreateCanvasChain();
848   RethinkDisplayViewports();
849   ResizeLayersToCanvases();
850 }
851 
852 void
DupLayoutCv(cvf,cvt,save)853 DupLayoutCv(cvf, cvt, save)
854 struct canvas *cvf, *cvt;
855 int save;
856 {
857   while(cvf)
858     {
859       cvt->c_slorient = cvf->c_slorient;
860       cvt->c_slweight = cvf->c_slweight;
861       if (cvf == D_forecv)
862         D_forecv = cvt;
863       if (!save)
864 	{
865 	  cvt->c_display = display;
866 	  if (!cvf->c_slperp)
867 	    {
868 	      cvt->c_captev.type = EV_TIMEOUT;
869 	      cvt->c_captev.data = (char *)cvt;
870 	      cvt->c_captev.handler = cv_winid_fn;
871 	      cvt->c_blank.l_cvlist = 0;
872 	      cvt->c_blank.l_layfn = &BlankLf;
873 	      cvt->c_blank.l_bottom = &cvt->c_blank;
874 	    }
875           cvt->c_layer = cvf->c_layer;
876 	}
877       else
878 	{
879 	  struct win *p = cvf->c_layer ? Layer2Window(cvf->c_layer) : 0;
880           cvt->c_layer = p ? &p->w_layer : 0;
881 	}
882       if (cvf->c_slperp)
883 	{
884 	  cvt->c_slperp = (struct canvas *)calloc(1, sizeof(struct canvas));
885 	  cvt->c_slperp->c_slback = cvt;
886 	  CanvasInitBlank(cvt->c_slperp);
887 	  DupLayoutCv(cvf->c_slperp, cvt->c_slperp, save);
888 	}
889       if (cvf->c_slnext)
890 	{
891 	  cvt->c_slnext = (struct canvas *)calloc(1, sizeof(struct canvas));
892 	  cvt->c_slnext->c_slprev = cvt;
893 	  cvt->c_slnext->c_slback = cvt->c_slback;
894 	  CanvasInitBlank(cvt->c_slnext);
895 	}
896       cvf = cvf->c_slnext;
897       cvt = cvt->c_slnext;
898     }
899 }
900 
901 void
PutWindowCv(cv)902 PutWindowCv(cv)
903 struct canvas *cv;
904 {
905   struct win *p;
906   for (; cv; cv = cv->c_slnext)
907     {
908       if (cv->c_slperp)
909 	{
910 	  PutWindowCv(cv->c_slperp);
911 	  continue;
912 	}
913       p = cv->c_layer ? (struct win *)cv->c_layer->l_data : 0;
914       cv->c_layer = 0;
915       SetCanvasWindow(cv, p);
916     }
917 }
918 
919