918 lines
21 KiB
C
918 lines
21 KiB
C
/* 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
|
|
* https://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 = (D_has_hstatus == HSTATUS_FIRSTLINE);
|
|
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 = 1; //FIXME Division by zero (got) is posible. "hx = 1" is random number here!!!
|
|
if (got != 0)
|
|
hx = need * (hh - m - 1) / got;
|
|
else
|
|
debug(" got = 0\n");
|
|
|
|
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 ye;
|
|
struct canvas *cv;
|
|
|
|
debug("RemCanvas\n");
|
|
cv = D_forecv;
|
|
ye = cv->c_slback->c_ye;
|
|
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);
|
|
}
|
|
/* 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);
|
|
}
|
|
}
|
|
|