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 * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
35 #include "list_generic.h"
39 static void CanvasInitBlank(Canvas
*cv
)
41 cv
->c_blank
.l_cvlist
= cv
;
42 cv
->c_blank
.l_width
= cv
->c_xe
- cv
->c_xs
+ 1;
43 cv
->c_blank
.l_height
= cv
->c_ye
- cv
->c_ys
+ 1;
44 cv
->c_blank
.l_x
= cv
->c_blank
.l_y
= 0;
45 cv
->c_blank
.l_layfn
= &BlankLf
;
46 cv
->c_blank
.l_data
= NULL
;
47 cv
->c_blank
.l_next
= NULL
;
48 cv
->c_blank
.l_bottom
= &cv
->c_blank
;
49 cv
->c_blank
.l_blocking
= 0;
50 cv
->c_layer
= &cv
->c_blank
;
53 static void FreePerp(Canvas
*pcv
)
60 cv
->c_slprev
= pcv
->c_slprev
;
62 cv
->c_slprev
->c_slnext
= cv
;
63 cv
->c_slback
= pcv
->c_slback
;
64 if (cv
->c_slback
&& cv
->c_slback
->c_slperp
== pcv
)
65 cv
->c_slback
->c_slperp
= cv
;
66 cv
->c_slorient
= pcv
->c_slorient
;
67 cv
->c_slweight
= pcv
->c_slweight
;
68 while (cv
->c_slnext
) {
70 cv
->c_slorient
= pcv
->c_slorient
;
71 cv
->c_slback
= pcv
->c_slback
;
72 cv
->c_slweight
= pcv
->c_slweight
;
74 cv
->c_slnext
= pcv
->c_slnext
;
76 cv
->c_slnext
->c_slprev
= cv
;
77 LayerCleanupMemory(&pcv
->c_blank
);
81 void FreeCanvas(Canvas
*cv
)
87 cv
->c_slprev
->c_slnext
= cv
->c_slnext
;
89 cv
->c_slnext
->c_slprev
= cv
->c_slprev
;
90 if (cv
->c_slback
&& cv
->c_slback
->c_slperp
== cv
)
91 cv
->c_slback
->c_slperp
= cv
->c_slnext
? cv
->c_slnext
: cv
->c_slprev
;
94 FreeCanvas(cv
->c_slperp
);
95 LayerCleanupMemory(&cv
->c_blank
);
103 /* remove from canvas chain as SetCanvasWindow might call
104 * some layer function */
105 for (Canvas
**cvp
= &D_cvlist
; *cvp
; cvp
= &(*cvp
)->c_next
)
111 win
= cv
->c_layer
? Layer2Window(cv
->c_layer
) : NULL
;
112 SetCanvasWindow(cv
, NULL
);
114 WindowChanged(win
, 'u');
115 if (flayer
== cv
->c_layer
)
117 for (vp
= cv
->c_vplist
; vp
; vp
= nvp
) {
123 evdeq(&cv
->c_captev
);
124 LayerCleanupMemory(&cv
->c_blank
);
128 int CountCanvas(Canvas
*cv
)
131 for (; cv
; cv
= cv
->c_slnext
) {
133 num
+= CountCanvasPerp(cv
);
140 int CountCanvasPerp(Canvas
*cv
)
143 for (Canvas
*cvp
= cv
->c_slperp
; cvp
; cvp
= cvp
->c_slnext
)
145 int n
= CountCanvas(cvp
->c_slperp
);
152 Canvas
*FindCanvas(int x
, int y
)
157 for (Canvas
*cv
= D_cvlist
; cv
; cv
= cv
->c_next
) {
158 if (x
>= cv
->c_xs
&& x
<= cv
->c_xe
) {
159 if (y
>= cv
->c_ys
&& y
<= cv
->c_ye
)
161 if (captiontop
&& y
== cv
->c_ys
- 1)
163 if (!captiontop
&& y
== cv
->c_ye
+ 1)
169 if (x
>= D_forecv
->c_xs
&& x
<= D_forecv
->c_xe
) {
170 if (x
< cv
->c_xs
|| x
> cv
->c_xe
)
172 if (y
< D_forecv
->c_ys
&& y
< cv
->c_ys
)
174 if (y
> D_forecv
->c_ye
+ 1 && y
> cv
->c_ye
+ 1)
178 if (y
> cv
->c_ye
+ 1)
179 m
= y
- (cv
->c_ye
+ 1);
181 if (y
>= D_forecv
->c_ys
&& y
<= D_forecv
->c_ye
+ 1) {
182 if (y
< cv
->c_ys
|| y
> cv
->c_ye
+ 1)
184 if (x
< D_forecv
->c_xs
&& x
< cv
->c_xs
)
186 if (x
> D_forecv
->c_xe
&& x
> cv
->c_xe
)
193 if (m
&& (!mm
|| m
< mm
)) {
198 return mcv
? mcv
: D_forecv
;
201 void SetCanvasWindow(Canvas
*cv
, Window
*window
)
203 Window
*p
= NULL
, **pp
;
208 display
= cv
->c_display
;
211 /* remove old layer */
212 for (cvpp
= &l
->l_cvlist
; (cvp
= *cvpp
); cvpp
= &cvp
->c_lnext
)
215 *cvpp
= cvp
->c_lnext
;
221 if (p
&& cv
== D_forecv
) {
222 ReleaseAutoWritelock(display
, p
);
224 SetTimeout(&p
->w_silenceev
, p
->w_silencewait
* 1000);
225 evenq(&p
->w_silenceev
);
230 if (l
->l_cvlist
== NULL
&& (p
== NULL
|| l
!= p
->w_savelayer
))
234 /* find right layer to display on canvas */
235 if (window
&& window
->w_type
!= W_TYPE_GROUP
) {
236 l
= &window
->w_layer
;
237 if (window
->w_savelayer
&& (window
->w_blocked
|| window
->w_savelayer
->l_cvlist
== NULL
))
238 l
= window
->w_savelayer
;
242 l
->l_data
= (char *)window
;
247 /* add our canvas to the layer's canvaslist */
248 cv
->c_lnext
= l
->l_cvlist
;
251 cv
->c_xoff
= cv
->c_xs
;
252 cv
->c_yoff
= cv
->c_ys
;
253 RethinkViewportOffsets(cv
);
258 if (window
&& window
->w_type
== W_TYPE_GROUP
) {
259 /* auto-start windowlist on groups */
260 Display
*d
= display
;
261 Layer
*oldflayer
= flayer
;
263 display_windows(0, 0, window
);
268 if (window
&& D_other
== window
)
269 D_other
= window
->w_prev_mru
; /* Might be 0, but that's OK. */
270 if (cv
== D_forecv
) {
272 fore
= D_fore
; /* XXX ? */
274 ObtainAutoWritelock(display
, window
);
276 * Place the window at the head of the most-recently-used list
278 if (mru_window
!= window
) {
279 for (pp
= &mru_window
; (p
= *pp
); pp
= &p
->w_prev_mru
)
283 p
->w_prev_mru
= mru_window
;
291 static void cv_winid_fn(Event
*ev
, void *data
)
294 Canvas
*cv
= (Canvas
*)data
;
296 display
= cv
->c_display
;
297 if (D_status
== STATUS_ON_WIN
) {
304 if (cv
->c_ye
+ 1 < D_height
)
305 RefreshLine(cv
->c_ye
+ 1, 0, D_width
- 1, 0);
306 if (ox
!= -1 && oy
!= -1)
310 int MakeDefaultCanvas(void)
314 if ((cv
= calloc(1, sizeof(Canvas
))) == NULL
)
317 cv
->c_xe
= D_width
- 1;
318 cv
->c_ys
= (D_has_hstatus
== HSTATUS_FIRSTLINE
) + captionalways
* captiontop
;
319 cv
->c_ye
= D_height
- 1 - (D_has_hstatus
== HSTATUS_LASTLINE
) - captionalways
* !captiontop
;
323 cv
->c_display
= display
;
329 cv
->c_slback
= &D_canvas
;
330 D_canvas
.c_slperp
= cv
;
331 D_canvas
.c_xs
= cv
->c_xs
;
332 D_canvas
.c_xe
= cv
->c_xe
;
333 D_canvas
.c_ys
= cv
->c_ys
;
334 D_canvas
.c_ye
= cv
->c_ye
;
335 cv
->c_slorient
= SLICE_UNKN
;
336 cv
->c_captev
.type
= EV_TIMEOUT
;
337 cv
->c_captev
.data
= (char *)cv
;
338 cv
->c_captev
.handler
= cv_winid_fn
;
344 RethinkDisplayViewports();
345 D_forecv
= cv
; /* default input focus */
349 static Canvas
**CreateCanvasChainRec(Canvas
*cv
, Canvas
**cvp
)
351 for (; cv
; cv
= cv
->c_slnext
) {
353 cvp
= CreateCanvasChainRec(cv
->c_slperp
, cvp
);
362 void RecreateCanvasChain(void)
365 cvp
= CreateCanvasChainRec(D_canvas
.c_slperp
, &D_cvlist
);
369 void EqualizeCanvas(Canvas
*cv
, bool gflag
)
371 for (; cv
; cv
= cv
->c_slnext
) {
372 if (cv
->c_slperp
&& gflag
) {
373 cv
->c_slweight
= CountCanvasPerp(cv
);
374 for (Canvas
*cv2
= cv
->c_slperp
; cv2
; cv2
= cv2
->c_slnext
)
376 EqualizeCanvas(cv2
->c_slperp
, gflag
);
382 void ResizeCanvas(Canvas
*cv
)
384 Canvas
*cv2
, *cvn
, *fcv
;
385 int nh
, i
, maxi
, hh
, m
, w
, wsum
;
397 if (cv
->c_slorient
== SLICE_UNKN
) {
402 cv
->c_xoff
= cv
->c_xs
;
403 cv
->c_yoff
= cv
->c_ys
;
404 cv
->c_blank
.l_width
= cv
->c_xe
- cv
->c_xs
+ 1;
405 cv
->c_blank
.l_height
= cv
->c_ye
- cv
->c_ys
+ 1;
410 if (focusminwidth
|| focusminheight
) {
412 while (cv2
->c_slback
) {
413 if (cv2
->c_slback
== cv
->c_slback
) {
415 focusmin
= cv
->c_slorient
== SLICE_VERT
? focusminheight
: focusminwidth
;
418 else if (focusmin
< 0)
419 focusmin
= cv
->c_slorient
== SLICE_VERT
? ye
- ys
+ 2 : xe
- xs
+ 2;
425 m
= CountCanvas(cv
) * 2;
426 nh
= cv
->c_slorient
== SLICE_VERT
? ye
- ys
+ 2 : xe
- xs
+ 2;
434 /* pass 1: calculate weight sum */
435 for (cv2
= cv
, wsum
= 0; cv2
; cv2
= cv2
->c_slnext
) {
436 wsum
+= cv2
->c_slweight
;
442 /* pass 2: calculate need/excess space */
443 nh
= cv
->c_slorient
== SLICE_VERT
? ye
- ys
+ 2 : xe
- xs
+ 2;
444 for (cv2
= cv
, need
= got
= 0; cv2
; cv2
= cv2
->c_slnext
) {
445 m
= cv2
->c_slperp
? CountCanvasPerp(cv2
) * 2 - 1 : 1;
448 hh
= cv2
->c_slweight
? nh
* cv2
->c_slweight
/ w
: 0;
449 w
-= cv2
->c_slweight
;
459 /* pass 3: distribute space */
460 nh
= cv
->c_slorient
== SLICE_VERT
? ye
- ys
+ 2 : xe
- xs
+ 2;
461 i
= cv
->c_slorient
== SLICE_VERT
? ys
: xs
;
462 maxi
= cv
->c_slorient
== SLICE_VERT
? ye
: xe
;
464 for (; cv
; cv
= cvn
) {
467 if (cv
->c_slprev
&& !cv
->c_slback
->c_slback
&& !cv
->c_slprev
->c_slperp
468 && !cv
->c_slprev
->c_slprev
) {
469 cv
->c_slprev
->c_slorient
= SLICE_UNKN
;
470 if (!captionalways
) {
472 cv
->c_slback
->c_ys
--;
473 cv
->c_slprev
->c_ys
--;
475 cv
->c_slback
->c_ye
++;
476 cv
->c_slprev
->c_ye
++;
480 SetCanvasWindow(cv
, NULL
);
484 m
= cv
->c_slperp
? CountCanvasPerp(cv
) * 2 - 1 : 1;
487 hh
= cv
->c_slweight
? nh
* cv
->c_slweight
/ w
: 0;
493 int hx
= need
* (hh
- m
- 1) / got
;
498 /* hh is window size plus pation line */
499 if (i
+ hh
> maxi
+ 2) {
502 if (i
+ hh
== maxi
+ 1) {
505 if (cv
->c_slorient
== SLICE_VERT
) {
509 cv
->c_ye
= i
+ hh
- 2;
514 cv
->c_xe
= i
+ hh
- 2;
520 cv
->c_xoff
= cv
->c_xs
;
521 cv
->c_yoff
= cv
->c_ys
;
522 cv
->c_blank
.l_width
= cv
->c_xe
- cv
->c_xs
+ 1;
523 cv
->c_blank
.l_height
= cv
->c_ye
- cv
->c_ys
+ 1;
526 if (!cv
->c_slperp
->c_slnext
) {
527 FreePerp(cv
->c_slperp
);
535 static Canvas
*AddPerp(Canvas
*cv
)
539 if ((pcv
= calloc(1, sizeof(Canvas
))) == NULL
)
542 pcv
->c_display
= cv
->c_display
;
543 pcv
->c_slnext
= cv
->c_slnext
;
544 pcv
->c_slprev
= cv
->c_slprev
;
546 pcv
->c_slback
= cv
->c_slback
;
547 if (cv
->c_slback
&& cv
->c_slback
->c_slperp
== cv
)
548 cv
->c_slback
->c_slperp
= pcv
;
549 pcv
->c_slorient
= cv
->c_slorient
;
552 pcv
->c_xs
= cv
->c_xs
;
553 pcv
->c_xe
= cv
->c_xe
;
554 pcv
->c_ys
= cv
->c_ys
;
555 pcv
->c_ye
= cv
->c_ye
;
557 pcv
->c_slnext
->c_slprev
= pcv
;
559 pcv
->c_slprev
->c_slnext
= pcv
;
560 pcv
->c_slweight
= cv
->c_slweight
;
561 CanvasInitBlank(pcv
);
567 cv
->c_slorient
= SLICE_UNKN
;
571 int AddCanvas(int orient
)
579 if (cv
->c_slorient
!= SLICE_UNKN
&& cv
->c_slorient
!= orient
)
584 xs
= cv
->c_slback
->c_xs
;
585 xe
= cv
->c_slback
->c_xe
;
586 ys
= cv
->c_slback
->c_ys
;
587 ye
= cv
->c_slback
->c_ye
;
588 if (!captionalways
&& cv
== D_canvas
.c_slperp
&& !cv
->c_slnext
) {
590 ys
++; /* need space for caption */
592 ye
--; /* need space for caption */
595 num
= CountCanvas(cv
->c_slback
->c_slperp
) + 1;
596 if (orient
== SLICE_VERT
)
603 return -1; /* can't fit in */
605 if ((cv
= calloc(1, sizeof(Canvas
))) == NULL
)
608 D_forecv
->c_slback
->c_ys
= ys
; /* in case we modified it above */
609 D_forecv
->c_slback
->c_ye
= ye
; /* in case we modified it above */
610 D_forecv
->c_slorient
= orient
; /* in case it was UNKN */
611 cv
->c_slnext
= D_forecv
->c_slnext
;
612 cv
->c_slprev
= D_forecv
;
613 D_forecv
->c_slnext
= cv
;
615 cv
->c_slnext
->c_slprev
= cv
;
616 cv
->c_slorient
= orient
;
617 cv
->c_slback
= D_forecv
->c_slback
;
625 cv
->c_display
= display
;
627 cv
->c_captev
.type
= EV_TIMEOUT
;
628 cv
->c_captev
.data
= (char *)cv
;
629 cv
->c_captev
.handler
= cv_winid_fn
;
637 EqualizeCanvas(cv
->c_slperp
, 0);
639 RecreateCanvasChain();
640 RethinkDisplayViewports();
641 ResizeLayersToCanvases();
652 ys
= cv
->c_slback
->c_ys
;
653 ye
= cv
->c_slback
->c_ye
;
655 if (cv
->c_slorient
== SLICE_UNKN
)
661 if (!cv
->c_slnext
->c_slnext
&& cv
->c_slback
->c_slback
) {
662 /* two canvases in slice, kill perp node */
664 FreePerp(cv
->c_slprev
? cv
->c_slprev
: cv
->c_slnext
);
665 FreePerp(cv
->c_slback
);
669 D_forecv
= cv
->c_slprev
;
671 D_forecv
= cv
->c_slnext
;
675 while (D_forecv
->c_slperp
)
676 D_forecv
= D_forecv
->c_slperp
;
678 /* if only one canvas left, set orient back to unknown */
679 if (!cv
->c_slnext
&& !cv
->c_slprev
&& !cv
->c_slback
->c_slback
&& !cv
->c_slperp
) {
680 cv
->c_slorient
= SLICE_UNKN
;
681 if (!captionalways
) {
683 cv
->c_slback
->c_ys
= --ys
; /* caption line no longer needed */
685 cv
->c_slback
->c_ye
= ++ye
; /* caption line no longer needed */
689 EqualizeCanvas(cv
->c_slperp
, 0);
692 D_fore
= Layer2Window(D_forecv
->c_layer
);
693 flayer
= D_forecv
->c_layer
;
695 RecreateCanvasChain();
696 RethinkDisplayViewports();
697 ResizeLayersToCanvases();
702 Canvas
*cv
= D_forecv
, *ocv
= NULL
;
706 cv
->c_slprev
->c_slnext
= cv
->c_slnext
;
710 cv
->c_slnext
->c_slprev
= cv
->c_slprev
;
714 if (cv
->c_slback
&& cv
->c_slback
->c_slperp
== cv
)
715 cv
->c_slback
->c_slperp
= ocv
;
716 cv
->c_slorient
= SLICE_UNKN
;
717 while (D_canvas
.c_slperp
)
718 FreeCanvas(D_canvas
.c_slperp
);
720 D_canvas
.c_slperp
= cv
;
721 cv
->c_slback
= &D_canvas
;
724 if (!captionalways
) {
726 D_canvas
.c_ys
--; /* caption line no longer needed */
728 D_canvas
.c_ye
++; /* caption line no longer needed */
730 ResizeCanvas(&D_canvas
);
731 RecreateCanvasChain();
732 RethinkDisplayViewports();
733 ResizeLayersToCanvases();
736 void DupLayoutCv(Canvas
*cvf
, Canvas
*cvt
, bool save
)
739 cvt
->c_slorient
= cvf
->c_slorient
;
740 cvt
->c_slweight
= cvf
->c_slweight
;
744 cvt
->c_display
= display
;
745 if (!cvf
->c_slperp
) {
746 cvt
->c_captev
.type
= EV_TIMEOUT
;
747 cvt
->c_captev
.data
= (char *)cvt
;
748 cvt
->c_captev
.handler
= cv_winid_fn
;
749 cvt
->c_blank
.l_cvlist
= NULL
;
750 cvt
->c_blank
.l_layfn
= &BlankLf
;
751 cvt
->c_blank
.l_bottom
= &cvt
->c_blank
;
753 cvt
->c_layer
= cvf
->c_layer
;
755 Window
*p
= cvf
->c_layer
? Layer2Window(cvf
->c_layer
) : NULL
;
756 cvt
->c_layer
= p
? &p
->w_layer
: NULL
;
759 cvt
->c_slperp
= calloc(1, sizeof(Canvas
));
760 cvt
->c_slperp
->c_slback
= cvt
;
761 CanvasInitBlank(cvt
->c_slperp
);
762 DupLayoutCv(cvf
->c_slperp
, cvt
->c_slperp
, save
);
765 cvt
->c_slnext
= calloc(1, sizeof(Canvas
));
766 cvt
->c_slnext
->c_slprev
= cvt
;
767 cvt
->c_slnext
->c_slback
= cvt
->c_slback
;
768 CanvasInitBlank(cvt
->c_slnext
);
775 void PutWindowCv(Canvas
*cv
)
778 for (; cv
; cv
= cv
->c_slnext
) {
780 PutWindowCv(cv
->c_slperp
);
783 p
= cv
->c_layer
? (Window
*)cv
->c_layer
->l_data
: NULL
;
785 SetCanvasWindow(cv
, p
);