summaryrefslogtreecommitdiff
path: root/src/canvas.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/canvas.c')
-rw-r--r--src/canvas.c916
1 files changed, 916 insertions, 0 deletions
diff --git a/src/canvas.c b/src/canvas.c
new file mode 100644
index 0000000..0121892
--- /dev/null
+++ b/src/canvas.c
@@ -0,0 +1,916 @@
+/* Copyright (c) 2008, 2009
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Micah Cowan (micah@cowan.name)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, see
+ * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+#include "canvas.h"
+#include "list_generic.h"
+
+extern struct display *display;
+extern struct win *fore, *windows;
+extern struct layer *flayer;
+extern int captionalways;
+extern struct LayFuncs BlankLf;
+extern int focusminwidth, focusminheight;
+
+static void
+CanvasInitBlank(cv)
+struct canvas *cv;
+{
+ cv->c_blank.l_cvlist = cv;
+ cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
+ cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
+ cv->c_blank.l_x = cv->c_blank.l_y = 0;
+ cv->c_blank.l_layfn = &BlankLf;
+ cv->c_blank.l_data = 0;
+ cv->c_blank.l_next = 0;
+ cv->c_blank.l_bottom = &cv->c_blank;
+ cv->c_blank.l_blocking = 0;
+ cv->c_layer = &cv->c_blank;
+}
+
+static void
+FreePerp(pcv)
+struct canvas *pcv;
+{
+ struct canvas *cv;
+
+ if (!pcv->c_slperp)
+ return;
+ cv = pcv->c_slperp;
+ cv->c_slprev = pcv->c_slprev;
+ if (cv->c_slprev)
+ cv->c_slprev->c_slnext = cv;
+ cv->c_slback = pcv->c_slback;
+ if (cv->c_slback && cv->c_slback->c_slperp == pcv)
+ cv->c_slback->c_slperp = cv;
+ cv->c_slorient = pcv->c_slorient;
+ cv->c_slweight = pcv->c_slweight;
+ while (cv->c_slnext)
+ {
+ cv = cv->c_slnext;
+ cv->c_slorient = pcv->c_slorient;
+ cv->c_slback = pcv->c_slback;
+ cv->c_slweight = pcv->c_slweight;
+ }
+ cv->c_slnext = pcv->c_slnext;
+ if (cv->c_slnext)
+ cv->c_slnext->c_slprev = cv;
+ LayerCleanupMemory(&pcv->c_blank);
+ free(pcv);
+}
+
+void
+FreeCanvas(cv)
+struct canvas *cv;
+{
+ struct viewport *vp, *nvp;
+ struct canvas **cvp;
+ struct win *p;
+
+ if (cv->c_slprev)
+ cv->c_slprev->c_slnext = cv->c_slnext;
+ if (cv->c_slnext)
+ cv->c_slnext->c_slprev = cv->c_slprev;
+ if (cv->c_slback && cv->c_slback->c_slperp == cv)
+ cv->c_slback->c_slperp = cv->c_slnext ? cv->c_slnext : cv->c_slprev;
+ if (cv->c_slperp)
+ {
+ while (cv->c_slperp)
+ FreeCanvas(cv->c_slperp);
+ LayerCleanupMemory(&cv->c_blank);
+ free(cv);
+ return;
+ }
+
+ if (display)
+ {
+ if (D_forecv == cv)
+ D_forecv = 0;
+ /* remove from canvas chain as SetCanvasWindow might call
+ * some layer function */
+ for (cvp = &D_cvlist; *cvp ; cvp = &(*cvp)->c_next)
+ if (*cvp == cv)
+ {
+ *cvp = cv->c_next;
+ break;
+ }
+ }
+ p = cv->c_layer ? Layer2Window(cv->c_layer) : 0;
+ SetCanvasWindow(cv, 0);
+ if (p)
+ WindowChanged(p, 'u');
+ if (flayer == cv->c_layer)
+ flayer = 0;
+ for (vp = cv->c_vplist; vp; vp = nvp)
+ {
+ vp->v_canvas = 0;
+ nvp = vp->v_next;
+ vp->v_next = 0;
+ free(vp);
+ }
+ evdeq(&cv->c_captev);
+ LayerCleanupMemory(&cv->c_blank);
+ free(cv);
+}
+
+int
+CountCanvas(cv)
+struct canvas *cv;
+{
+ int num = 0;
+ for (; cv; cv = cv->c_slnext)
+ {
+ if (cv->c_slperp)
+ {
+ struct canvas *cvp;
+ int nump = 1, n;
+ for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
+ if (cvp->c_slperp)
+ {
+ n = CountCanvas(cvp->c_slperp);
+ if (n > nump)
+ nump = n;
+ }
+ num += nump;
+ }
+ else
+ num++;
+ }
+ return num;
+}
+
+int
+CountCanvasPerp(cv)
+struct canvas *cv;
+{
+ struct canvas *cvp;
+ int num = 1, n;
+ for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
+ if (cvp->c_slperp)
+ {
+ n = CountCanvas(cvp->c_slperp);
+ if (n > num)
+ num = n;
+ }
+ return num;
+}
+
+struct canvas *
+FindCanvas(x, y)
+int x, y;
+{
+ struct canvas *cv, *mcv = 0;
+ int m, mm = 0;
+
+ for (cv = D_cvlist; cv; cv = cv->c_next)
+ {
+ /* ye + 1 because of caption line */
+ if (x >= cv->c_xs && x <= cv->c_xe && y >= cv->c_ys && y <= cv->c_ye + 1)
+ return cv;
+ if (cv == D_forecv)
+ continue;
+ m = 0;
+ if (x >= D_forecv->c_xs && x <= D_forecv->c_xe)
+ {
+ if (x < cv->c_xs || x > cv->c_xe)
+ continue;
+ if (y < D_forecv->c_ys && y < cv->c_ys)
+ continue;
+ if (y > D_forecv->c_ye + 1 && y > cv->c_ye + 1)
+ continue;
+ if (y < cv->c_ys)
+ m = cv->c_ys - y;
+ if (y > cv->c_ye + 1)
+ m = y - (cv->c_ye + 1);
+ }
+ if (y >= D_forecv->c_ys && y <= D_forecv->c_ye + 1)
+ {
+ if (y < cv->c_ys || y > cv->c_ye + 1)
+ continue;
+ if (x < D_forecv->c_xs && x < cv->c_xs)
+ continue;
+ if (x > D_forecv->c_xe && x > cv->c_xe)
+ continue;
+ if (x < cv->c_xs)
+ m = cv->c_xs - x;
+ if (x > cv->c_xe)
+ m = x - cv->c_xe;
+ }
+ if (m && (!mm || m < mm))
+ {
+ mcv = cv;
+ mm = m;
+ }
+ }
+ return mcv ? mcv : D_forecv;
+}
+
+void
+SetCanvasWindow(cv, wi)
+struct canvas *cv;
+struct win *wi;
+{
+ struct win *p = 0, **pp;
+ struct layer *l;
+ struct canvas *cvp, **cvpp;
+
+ l = cv->c_layer;
+ display = cv->c_display;
+
+ if (l)
+ {
+ /* remove old layer */
+ for (cvpp = &l->l_cvlist; (cvp = *cvpp); cvpp = &cvp->c_lnext)
+ if (cvp == cv)
+ break;
+ ASSERT(cvp);
+ *cvpp = cvp->c_lnext;
+
+ p = Layer2Window(l);
+ l = cv->c_layer;
+ cv->c_layer = 0;
+
+ if (p && cv == D_forecv)
+ {
+#ifdef MULTIUSER
+ ReleaseAutoWritelock(display, p);
+#endif
+ if (p->w_silence)
+ {
+ SetTimeout(&p->w_silenceev, p->w_silencewait * 1000);
+ evenq(&p->w_silenceev);
+ }
+ D_other = fore;
+ D_fore = 0;
+ }
+ if (l->l_cvlist == 0 && (p == 0 || l != p->w_savelayer))
+ KillLayerChain(l);
+ }
+
+ /* find right layer to display on canvas */
+ if (wi && wi->w_type != W_TYPE_GROUP)
+ {
+ l = &wi->w_layer;
+ if (wi->w_savelayer && (wi->w_blocked || wi->w_savelayer->l_cvlist == 0))
+ l = wi->w_savelayer;
+ }
+ else
+ {
+ l = &cv->c_blank;
+ if (wi)
+ l->l_data = (char *)wi;
+ else
+ l->l_data = 0;
+ }
+
+ /* add our canvas to the layer's canvaslist */
+ ASSERT(l->l_cvlist != cv);
+ cv->c_lnext = l->l_cvlist;
+ l->l_cvlist = cv;
+ cv->c_layer = l;
+ cv->c_xoff = cv->c_xs;
+ cv->c_yoff = cv->c_ys;
+ RethinkViewportOffsets(cv);
+
+ if (flayer == 0)
+ flayer = l;
+
+ if (wi && wi->w_type == W_TYPE_GROUP)
+ {
+ /* auto-start windowlist on groups */
+ struct display *d = display;
+ struct layer *oldflayer = flayer;
+ flayer = l;
+ display_windows(0, 0, wi);
+ flayer = oldflayer;
+ display = d;
+ }
+
+ if (wi && D_other == wi)
+ D_other = wi->w_next; /* Might be 0, but that's OK. */
+ if (cv == D_forecv)
+ {
+ D_fore = wi;
+ fore = D_fore; /* XXX ? */
+ if (wi)
+ {
+#ifdef MULTIUSER
+ ObtainAutoWritelock(display, wi);
+#endif
+ /*
+ * Place the window at the head of the most-recently-used list
+ */
+ if (windows != wi)
+ {
+ for (pp = &windows; (p = *pp); pp = &p->w_next)
+ if (p == wi)
+ break;
+ ASSERT(p);
+ *pp = p->w_next;
+ p->w_next = windows;
+ windows = p;
+ WListLinkChanged();
+ }
+ }
+ }
+}
+
+static void
+cv_winid_fn(ev, data)
+struct event *ev;
+char *data;
+{
+ int ox, oy;
+ struct canvas *cv = (struct canvas *)data;
+
+ display = cv->c_display;
+ if (D_status == STATUS_ON_WIN)
+ {
+ SetTimeout(ev, 1);
+ evenq(ev);
+ return;
+ }
+ ox = D_x;
+ oy = D_y;
+ if (cv->c_ye + 1 < D_height)
+ RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
+ if (ox != -1 && oy != -1)
+ GotoPos(ox, oy);
+}
+
+int
+MakeDefaultCanvas()
+{
+ struct canvas *cv;
+
+ ASSERT(display);
+ if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
+ return -1;
+ cv->c_xs = 0;
+ cv->c_xe = D_width - 1;
+ cv->c_ys = 0;
+ cv->c_ye = D_height - 1 - (D_has_hstatus == HSTATUS_LASTLINE) - captionalways;
+ debug2("MakeDefaultCanvas 0,0 %d,%d\n", cv->c_xe, cv->c_ye);
+ cv->c_xoff = 0;
+ cv->c_yoff = 0;
+ cv->c_next = 0;
+ cv->c_display = display;
+ cv->c_vplist = 0;
+ cv->c_slnext = 0;
+ cv->c_slprev = 0;
+ cv->c_slperp = 0;
+ cv->c_slweight = 1;
+ cv->c_slback = &D_canvas;
+ D_canvas.c_slperp = cv;
+ D_canvas.c_xs = cv->c_xs;
+ D_canvas.c_xe = cv->c_xe;
+ D_canvas.c_ys = cv->c_ys;
+ D_canvas.c_ye = cv->c_ye;
+ cv->c_slorient = SLICE_UNKN;
+ cv->c_captev.type = EV_TIMEOUT;
+ cv->c_captev.data = (char *)cv;
+ cv->c_captev.handler = cv_winid_fn;
+
+ CanvasInitBlank(cv);
+ cv->c_lnext = 0;
+
+ D_cvlist = cv;
+ RethinkDisplayViewports();
+ D_forecv = cv; /* default input focus */
+ return 0;
+}
+
+static struct canvas **
+CreateCanvasChainRec(cv, cvp)
+struct canvas *cv;
+struct canvas **cvp;
+{
+ for (; cv; cv = cv->c_slnext)
+ {
+ if (cv->c_slperp)
+ cvp = CreateCanvasChainRec(cv->c_slperp, cvp);
+ else
+ {
+ *cvp = cv;
+ cvp = &cv->c_next;
+ }
+ }
+ return cvp;
+}
+
+void
+RecreateCanvasChain()
+{
+ struct canvas **cvp;
+ cvp = CreateCanvasChainRec(D_canvas.c_slperp, &D_cvlist);
+ *cvp = 0;
+}
+
+void
+EqualizeCanvas(cv, gflag)
+struct canvas *cv;
+int gflag;
+{
+ struct canvas *cv2;
+ for (; cv; cv = cv->c_slnext)
+ {
+ if (cv->c_slperp && gflag)
+ {
+ cv->c_slweight = CountCanvasPerp(cv);
+ for (cv2 = cv->c_slperp; cv2; cv2 = cv2->c_slnext)
+ if (cv2->c_slperp)
+ EqualizeCanvas(cv2->c_slperp, gflag);
+ }
+ else
+ cv->c_slweight = 1;
+ }
+}
+
+void
+ResizeCanvas(cv)
+struct canvas *cv;
+{
+ struct canvas *cv2, *cvn, *fcv;
+ int nh, i, maxi, hh, m, w, wsum;
+ int need, got;
+ int xs, ys, xe, ye;
+ int focusmin = 0;
+
+ xs = cv->c_xs;
+ ys = cv->c_ys;
+ xe = cv->c_xe;
+ ye = cv->c_ye;
+ cv = cv->c_slperp;
+ debug2("ResizeCanvas: %d,%d", xs, ys);
+ debug2(" %d,%d\n", xe, ye);
+ if (cv == 0)
+ return;
+ if (cv->c_slorient == SLICE_UNKN)
+ {
+ ASSERT(!cv->c_slnext && !cv->c_slperp);
+ cv->c_xs = xs;
+ cv->c_xe = xe;
+ cv->c_ys = ys;
+ cv->c_ye = ye;
+ cv->c_xoff = cv->c_xs;
+ cv->c_yoff = cv->c_ys;
+ cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
+ cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
+ return;
+ }
+
+ fcv = 0;
+ if (focusminwidth || focusminheight)
+ {
+ debug("searching for focus canvas\n");
+ cv2 = D_forecv;
+ while (cv2->c_slback)
+ {
+ if (cv2->c_slback == cv->c_slback)
+ {
+ fcv = cv2;
+ focusmin = cv->c_slorient == SLICE_VERT ? focusminheight : focusminwidth;
+ if (focusmin > 0)
+ focusmin--;
+ else if (focusmin < 0)
+ focusmin = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
+ debug1("found, focusmin=%d\n", focusmin);
+ }
+ cv2 = cv2->c_slback;
+ }
+ }
+ if (focusmin)
+ {
+ m = CountCanvas(cv) * 2;
+ nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
+ nh -= m;
+ if (nh < 0)
+ nh = 0;
+ if (focusmin > nh)
+ focusmin = nh;
+ debug1("corrected to %d\n", focusmin);
+ }
+
+ /* pass 1: calculate weight sum */
+ for (cv2 = cv, wsum = 0; cv2; cv2 = cv2->c_slnext)
+ {
+ debug1(" weight %d\n", cv2->c_slweight);
+ wsum += cv2->c_slweight;
+ }
+ debug1("wsum = %d\n", wsum);
+ if (wsum == 0)
+ wsum = 1;
+ w = wsum;
+
+ /* pass 2: calculate need/excess space */
+ nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
+ for (cv2 = cv, need = got = 0; cv2; cv2 = cv2->c_slnext)
+ {
+ m = cv2->c_slperp ? CountCanvasPerp(cv2) * 2 - 1 : 1;
+ if (cv2 == fcv)
+ m += focusmin;
+ hh = cv2->c_slweight ? nh * cv2->c_slweight / w : 0;
+ w -= cv2->c_slweight;
+ nh -= hh;
+ debug2(" should %d min %d\n", hh, m);
+ if (hh <= m + 1)
+ need += m + 1 - hh;
+ else
+ got += hh - m - 1;
+ }
+ debug2("need: %d, got %d\n", need, got);
+ if (need > got)
+ need = got;
+
+ /* pass 3: distribute space */
+ nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
+ i = cv->c_slorient == SLICE_VERT ? ys : xs;
+ maxi = cv->c_slorient == SLICE_VERT ? ye : xe;
+ w = wsum;
+ for (; cv; cv = cvn)
+ {
+ cvn = cv->c_slnext;
+ if (i > maxi)
+ {
+ if (cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slprev->c_slperp && !cv->c_slprev->c_slprev)
+ {
+ cv->c_slprev->c_slorient = SLICE_UNKN;
+ if (!captionalways)
+ {
+ cv->c_slback->c_ye++;
+ cv->c_slprev->c_ye++;
+ }
+ }
+ SetCanvasWindow(cv, 0);
+ FreeCanvas(cv);
+ continue;
+ }
+ m = cv->c_slperp ? CountCanvasPerp(cv) * 2 - 1 : 1;
+ if (cv == fcv)
+ m += focusmin;
+ hh = cv->c_slweight ? nh * cv->c_slweight / w : 0;
+ w -= cv->c_slweight;
+ nh -= hh;
+ debug2(" should %d min %d\n", hh, m);
+ if (hh <= m + 1)
+ {
+ hh = m + 1;
+ debug1(" -> %d\n", hh);
+ }
+ else
+ {
+ int hx = need * (hh - m - 1) / got;
+ debug3(" -> %d - %d = %d\n", hh, hx, hh - hx);
+ got -= (hh - m - 1);
+ hh -= hx;
+ need -= hx;
+ debug2(" now need=%d got=%d\n", need, got);
+ }
+ ASSERT(hh >= m + 1);
+ /* hh is window size plus pation line */
+ if (i + hh > maxi + 2)
+ {
+ hh = maxi + 2 - i;
+ debug1(" not enough space, reducing to %d\n", hh);
+ }
+ if (i + hh == maxi + 1)
+ {
+ hh++;
+ debug(" incrementing as no other canvas will fit\n");
+ }
+ if (cv->c_slorient == SLICE_VERT)
+ {
+ cv->c_xs = xs;
+ cv->c_xe = xe;
+ cv->c_ys = i;
+ cv->c_ye = i + hh - 2;
+ cv->c_xoff = xs;
+ cv->c_yoff = i;
+ }
+ else
+ {
+ cv->c_xs = i;
+ cv->c_xe = i + hh - 2;
+ cv->c_ys = ys;
+ cv->c_ye = ye;
+ cv->c_xoff = i;
+ cv->c_yoff = ys;
+ }
+ cv->c_xoff = cv->c_xs;
+ cv->c_yoff = cv->c_ys;
+ cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
+ cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
+ if (cv->c_slperp)
+ {
+ ResizeCanvas(cv);
+ if (!cv->c_slperp->c_slnext)
+ {
+ debug("deleting perp node\n");
+ FreePerp(cv->c_slperp);
+ FreePerp(cv);
+ }
+ }
+ i += hh;
+ }
+}
+
+static struct canvas *
+AddPerp(cv)
+struct canvas *cv;
+{
+ struct canvas *pcv;
+ debug("Creating new perp node\n");
+
+ if ((pcv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
+ return 0;
+ pcv->c_next = 0;
+ pcv->c_display = cv->c_display;
+ pcv->c_slnext = cv->c_slnext;
+ pcv->c_slprev = cv->c_slprev;
+ pcv->c_slperp = cv;
+ pcv->c_slback = cv->c_slback;
+ if (cv->c_slback && cv->c_slback->c_slperp == cv)
+ cv->c_slback->c_slperp = pcv;
+ pcv->c_slorient = cv->c_slorient;
+ pcv->c_xoff = 0;
+ pcv->c_yoff = 0;
+ pcv->c_xs = cv->c_xs;
+ pcv->c_xe = cv->c_xe;
+ pcv->c_ys = cv->c_ys;
+ pcv->c_ye = cv->c_ye;
+ if (pcv->c_slnext)
+ pcv->c_slnext->c_slprev = pcv;
+ if (pcv->c_slprev)
+ pcv->c_slprev->c_slnext = pcv;
+ pcv->c_slweight = cv->c_slweight;
+ CanvasInitBlank(pcv);
+ cv->c_slweight = 1;
+ cv->c_slnext = 0;
+ cv->c_slprev = 0;
+ cv->c_slperp = 0;
+ cv->c_slback = pcv;
+ cv->c_slorient = SLICE_UNKN;
+ return pcv;
+}
+
+int
+AddCanvas(orient)
+int orient;
+{
+ struct canvas *cv;
+ int xs, xe, ys, ye;
+ int h, num;
+
+ cv = D_forecv;
+ debug2("AddCanvas orient %d, forecv is %d\n", orient, cv->c_slorient);
+
+ if (cv->c_slorient != SLICE_UNKN && cv->c_slorient != orient)
+ if (!AddPerp(cv))
+ return -1;
+
+ cv = D_forecv;
+ xs = cv->c_slback->c_xs;
+ xe = cv->c_slback->c_xe;
+ ys = cv->c_slback->c_ys;
+ ye = cv->c_slback->c_ye;
+ if (!captionalways && cv == D_canvas.c_slperp && !cv->c_slnext)
+ ye--; /* need space for caption */
+ debug2("Adding Canvas to slice %d,%d ", xs, ys);
+ debug2("%d,%d\n", xe, ye);
+
+ num = CountCanvas(cv->c_slback->c_slperp) + 1;
+ debug1("Num = %d\n", num);
+ if (orient == SLICE_VERT)
+ h = ye - ys + 1;
+ else
+ h = xe - xs + 1;
+
+ h -= 2 * num - 1;
+ if (h < 0)
+ return -1; /* can't fit in */
+
+ if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
+ return -1;
+
+ D_forecv->c_slback->c_ye = ye; /* in case we modified it above */
+ D_forecv->c_slorient = orient; /* in case it was UNKN */
+ cv->c_slnext = D_forecv->c_slnext;
+ cv->c_slprev = D_forecv;
+ D_forecv->c_slnext = cv;
+ if (cv->c_slnext)
+ cv->c_slnext->c_slprev = cv;
+ cv->c_slorient = orient;
+ cv->c_slback = D_forecv->c_slback;
+
+ cv->c_xs = xs;
+ cv->c_xe = xe;
+ cv->c_ys = ys;
+ cv->c_ye = ye;
+ cv->c_xoff = 0;
+ cv->c_yoff = 0;
+ cv->c_display = display;
+ cv->c_vplist = 0;
+ cv->c_captev.type = EV_TIMEOUT;
+ cv->c_captev.data = (char *)cv;
+ cv->c_captev.handler = cv_winid_fn;
+
+ CanvasInitBlank(cv);
+ cv->c_lnext = 0;
+
+ cv->c_next = 0;
+
+ cv = cv->c_slback;
+ EqualizeCanvas(cv->c_slperp, 0);
+ ResizeCanvas(cv);
+ RecreateCanvasChain();
+ RethinkDisplayViewports();
+ ResizeLayersToCanvases();
+ return 0;
+}
+
+void
+RemCanvas()
+{
+ int xs, xe, ys, ye;
+ struct canvas *cv;
+
+ debug("RemCanvas\n");
+ cv = D_forecv;
+ if (cv->c_slorient == SLICE_UNKN)
+ return;
+ while (cv->c_slprev)
+ cv = cv->c_slprev;
+ if (!cv->c_slnext)
+ return;
+ if (!cv->c_slnext->c_slnext && cv->c_slback->c_slback)
+ {
+ /* two canvases in slice, kill perp node */
+ cv = D_forecv;
+ debug("deleting perp node\n");
+ FreePerp(cv->c_slprev ? cv->c_slprev : cv->c_slnext);
+ FreePerp(cv->c_slback);
+ }
+ xs = cv->c_slback->c_xs;
+ xe = cv->c_slback->c_xe;
+ ys = cv->c_slback->c_ys;
+ ye = cv->c_slback->c_ye;
+ /* free canvas */
+ cv = D_forecv;
+ D_forecv = cv->c_slprev;
+ if (!D_forecv)
+ D_forecv = cv->c_slnext;
+ FreeCanvas(cv);
+
+ cv = D_forecv;
+ while (D_forecv->c_slperp)
+ D_forecv = D_forecv->c_slperp;
+
+ /* if only one canvas left, set orient back to unknown */
+ if (!cv->c_slnext && !cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slperp)
+ {
+ cv->c_slorient = SLICE_UNKN;
+ if (!captionalways)
+ cv->c_slback->c_ye = ++ye; /* caption line no longer needed */
+ }
+ cv = cv->c_slback;
+ EqualizeCanvas(cv->c_slperp, 0);
+ ResizeCanvas(cv);
+
+ D_fore = Layer2Window(D_forecv->c_layer);
+ flayer = D_forecv->c_layer;
+
+ RecreateCanvasChain();
+ RethinkDisplayViewports();
+ ResizeLayersToCanvases();
+}
+
+void
+OneCanvas()
+{
+ struct canvas *cv = D_forecv, *ocv = 0;
+
+ if (cv->c_slprev)
+ {
+ ocv = cv->c_slprev;
+ cv->c_slprev->c_slnext = cv->c_slnext;
+ }
+ if (cv->c_slnext)
+ {
+ ocv = cv->c_slnext;
+ cv->c_slnext->c_slprev = cv->c_slprev;
+ }
+ if (!ocv)
+ return;
+ if (cv->c_slback && cv->c_slback->c_slperp == cv)
+ cv->c_slback->c_slperp = ocv;
+ cv->c_slorient = SLICE_UNKN;
+ while (D_canvas.c_slperp)
+ FreeCanvas(D_canvas.c_slperp);
+ cv = D_forecv;
+ D_canvas.c_slperp = cv;
+ cv->c_slback = &D_canvas;
+ cv->c_slnext = 0;
+ cv->c_slprev = 0;
+ ASSERT(!cv->c_slperp);
+ if (!captionalways)
+ D_canvas.c_ye++; /* caption line no longer needed */
+ ResizeCanvas(&D_canvas);
+ RecreateCanvasChain();
+ RethinkDisplayViewports();
+ ResizeLayersToCanvases();
+}
+
+void
+DupLayoutCv(cvf, cvt, save)
+struct canvas *cvf, *cvt;
+int save;
+{
+ while(cvf)
+ {
+ cvt->c_slorient = cvf->c_slorient;
+ cvt->c_slweight = cvf->c_slweight;
+ if (cvf == D_forecv)
+ D_forecv = cvt;
+ if (!save)
+ {
+ cvt->c_display = display;
+ if (!cvf->c_slperp)
+ {
+ cvt->c_captev.type = EV_TIMEOUT;
+ cvt->c_captev.data = (char *)cvt;
+ cvt->c_captev.handler = cv_winid_fn;
+ cvt->c_blank.l_cvlist = 0;
+ cvt->c_blank.l_layfn = &BlankLf;
+ cvt->c_blank.l_bottom = &cvt->c_blank;
+ }
+ cvt->c_layer = cvf->c_layer;
+ }
+ else
+ {
+ struct win *p = cvf->c_layer ? Layer2Window(cvf->c_layer) : 0;
+ cvt->c_layer = p ? &p->w_layer : 0;
+ }
+ if (cvf->c_slperp)
+ {
+ cvt->c_slperp = (struct canvas *)calloc(1, sizeof(struct canvas));
+ cvt->c_slperp->c_slback = cvt;
+ CanvasInitBlank(cvt->c_slperp);
+ DupLayoutCv(cvf->c_slperp, cvt->c_slperp, save);
+ }
+ if (cvf->c_slnext)
+ {
+ cvt->c_slnext = (struct canvas *)calloc(1, sizeof(struct canvas));
+ cvt->c_slnext->c_slprev = cvt;
+ cvt->c_slnext->c_slback = cvt->c_slback;
+ CanvasInitBlank(cvt->c_slnext);
+ }
+ cvf = cvf->c_slnext;
+ cvt = cvt->c_slnext;
+ }
+}
+
+void
+PutWindowCv(cv)
+struct canvas *cv;
+{
+ struct win *p;
+ for (; cv; cv = cv->c_slnext)
+ {
+ if (cv->c_slperp)
+ {
+ PutWindowCv(cv->c_slperp);
+ continue;
+ }
+ p = cv->c_layer ? (struct win *)cv->c_layer->l_data : 0;
+ cv->c_layer = 0;
+ SetCanvasWindow(cv, p);
+ }
+}
+