Commit 91d2180e authored by Ivica Bukvic's avatar Ivica Bukvic Committed by Hans-Christoph Steiner
Browse files

Pd-0.42.5-extended-l2ork-dev-20111021.tar.bz2

parent 530090ac
/* Copyright (c) 1997-1999 Miller Puckette.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
/* send~, delread~, throw~, catch~ */
#include "m_pd.h"
extern int ugen_getsortno(void);
#define DEFDELVS 64 /* LATER get this from canvas at DSP time */
static int delread_zero = 0; /* four bytes of zero for delread~, vd~ */
/* ----------------------------- delwrite~ ----------------------------- */
static t_class *sigdelwrite_class;
typedef struct delwritectl
{
int c_n;
t_sample *c_vec;
int c_phase;
} t_delwritectl;
typedef struct _sigdelwrite
{
t_object x_obj;
t_symbol *x_sym;
t_delwritectl x_cspace;
int x_sortno; /* DSP sort number at which this was last put on chain */
int x_rsortno; /* DSP sort # for first delread or write in chain */
int x_vecsize; /* vector size for delread~ to use */
t_float x_f;
} t_sigdelwrite;
#define XTRASAMPS 4
#define SAMPBLK 4
/* routine to check that all delwrites/delreads/vds have same vecsize */
static void sigdelwrite_checkvecsize(t_sigdelwrite *x, int vecsize)
{
if (x->x_rsortno != ugen_getsortno())
{
x->x_vecsize = vecsize;
x->x_rsortno = ugen_getsortno();
}
/*
LATER this should really check sample rate and blocking, once that is
supported. Probably we don't actually care about vecsize.
For now just suppress this check. */
#if 0
else if (vecsize != x->x_vecsize)
pd_error(x, "delread/delwrite/vd vector size mismatch");
#endif
}
#include <stdio.h>
static void *sigdelwrite_new(t_symbol *s, t_floatarg msec)
{
int nsamps;
t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class);
if (!*s->s_name) s = gensym("delwrite~");
pd_bind(&x->x_obj.ob_pd, s);
x->x_sym = s;
if (msec == 0) msec = 1000;
nsamps = msec * sys_getsr() * (t_float)(0.001f);
if (nsamps < 1) nsamps = 1;
nsamps += ((- nsamps) & (SAMPBLK - 1));
nsamps += DEFDELVS;
x->x_cspace.c_n = nsamps;
x->x_cspace.c_vec =
(t_sample *)getbytes((nsamps + XTRASAMPS) * sizeof(t_sample));
x->x_cspace.c_phase = XTRASAMPS;
x->x_sortno = 0;
x->x_vecsize = 0;
x->x_f = 0;
return (x);
}
static t_int *sigdelwrite_perform(t_int *w)
{
t_sample *in = (t_sample *)(w[1]);
t_delwritectl *c = (t_delwritectl *)(w[2]);
int n = (int)(w[3]);
int phase = c->c_phase, nsamps = c->c_n;
t_sample *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
phase += n;
while (n--)
{
t_sample f = *in++;
if (PD_BIGORSMALL(f))
f = 0;
*bp++ = f;
if (bp == ep)
{
vp[0] = ep[-4];
vp[1] = ep[-3];
vp[2] = ep[-2];
vp[3] = ep[-1];
bp = vp + XTRASAMPS;
phase -= nsamps;
}
}
bp = vp + c->c_phase;
c->c_phase = phase;
return (w+4);
}
static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp)
{
dsp_add(sigdelwrite_perform, 3, sp[0]->s_vec, &x->x_cspace, sp[0]->s_n);
x->x_sortno = ugen_getsortno();
sigdelwrite_checkvecsize(x, sp[0]->s_n);
}
static void sigdelwrite_free(t_sigdelwrite *x)
{
pd_unbind(&x->x_obj.ob_pd, x->x_sym);
freebytes(x->x_cspace.c_vec,
(x->x_cspace.c_n + XTRASAMPS) * sizeof(t_sample));
}
static void sigdelwrite_setup(void)
{
sigdelwrite_class = class_new(gensym("delwrite~"),
(t_newmethod)sigdelwrite_new, (t_method)sigdelwrite_free,
sizeof(t_sigdelwrite), 0, A_DEFSYM, A_DEFFLOAT, 0);
CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, x_f);
class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_dsp,
gensym("dsp"), 0);
}
/* ----------------------------- delread~ ----------------------------- */
static t_class *sigdelread_class;
typedef struct _sigdelread
{
t_object x_obj;
t_symbol *x_sym;
t_float x_deltime; /* delay in msec */
int x_delsamps; /* delay in samples */
t_float x_sr; /* samples per msec */
t_float x_n; /* vector size */
int x_zerodel; /* 0 or vecsize depending on read/write order */
} t_sigdelread;
static void sigdelread_float(t_sigdelread *x, t_float f);
static void *sigdelread_new(t_symbol *s, t_floatarg f)
{
t_sigdelread *x = (t_sigdelread *)pd_new(sigdelread_class);
x->x_sym = s;
x->x_sr = 1;
x->x_n = 1;
x->x_zerodel = 0;
sigdelread_float(x, f);
outlet_new(&x->x_obj, &s_signal);
return (x);
}
static void sigdelread_float(t_sigdelread *x, t_float f)
{
int samps;
t_sigdelwrite *delwriter =
(t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
x->x_deltime = f;
if (delwriter)
{
int delsize = delwriter->x_cspace.c_n;
x->x_delsamps = (int)(0.5 + x->x_sr * x->x_deltime)
+ x->x_n - x->x_zerodel;
if (x->x_delsamps < x->x_n) x->x_delsamps = x->x_n;
else if (x->x_delsamps > delwriter->x_cspace.c_n - DEFDELVS)
x->x_delsamps = delwriter->x_cspace.c_n - DEFDELVS;
}
}
static t_int *sigdelread_perform(t_int *w)
{
t_sample *out = (t_sample *)(w[1]);
t_delwritectl *c = (t_delwritectl *)(w[2]);
int delsamps = *(int *)(w[3]);
int n = (int)(w[4]);
int phase = c->c_phase - delsamps, nsamps = c->c_n;
t_sample *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
if (phase < 0) phase += nsamps;
bp = vp + phase;
while (n--)
{
*out++ = *bp++;
if (bp == ep) bp -= nsamps;
}
return (w+5);
}
static void sigdelread_dsp(t_sigdelread *x, t_signal **sp)
{
t_sigdelwrite *delwriter =
(t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
x->x_sr = sp[0]->s_sr * 0.001;
x->x_n = sp[0]->s_n;
if (delwriter)
{
sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
0 : delwriter->x_vecsize);
sigdelread_float(x, x->x_deltime);
dsp_add(sigdelread_perform, 4,
sp[0]->s_vec, &delwriter->x_cspace, &x->x_delsamps, sp[0]->s_n);
}
else if (*x->x_sym->s_name)
error("delread~: %s: no such delwrite~",x->x_sym->s_name);
}
static void sigdelread_setup(void)
{
sigdelread_class = class_new(gensym("delread~"),
(t_newmethod)sigdelread_new, 0,
sizeof(t_sigdelread), 0, A_DEFSYM, A_DEFFLOAT, 0);
class_addmethod(sigdelread_class, (t_method)sigdelread_dsp,
gensym("dsp"), 0);
class_addfloat(sigdelread_class, (t_method)sigdelread_float);
}
/* ----------------------------- vd~ ----------------------------- */
static t_class *sigvd_class;
typedef struct _sigvd
{
t_object x_obj;
t_symbol *x_sym;
t_float x_sr; /* samples per msec */
int x_zerodel; /* 0 or vecsize depending on read/write order */
t_float x_f;
} t_sigvd;
static void *sigvd_new(t_symbol *s)
{
t_sigvd *x = (t_sigvd *)pd_new(sigvd_class);
if (!*s->s_name) s = gensym("vd~");
x->x_sym = s;
x->x_sr = 1;
x->x_zerodel = 0;
outlet_new(&x->x_obj, &s_signal);
x->x_f = 0;
return (x);
}
static t_int *sigvd_perform(t_int *w)
{
t_sample *in = (t_sample *)(w[1]);
t_sample *out = (t_sample *)(w[2]);
t_delwritectl *ctl = (t_delwritectl *)(w[3]);
t_sigvd *x = (t_sigvd *)(w[4]);
int n = (int)(w[5]);
int nsamps = ctl->c_n;
t_sample limit = nsamps - n - 1;
t_sample fn = n-1;
t_sample *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase;
t_sample zerodel = x->x_zerodel;
while (n--)
{
t_sample delsamps = x->x_sr * *in++ - zerodel, frac;
int idelsamps;
t_sample a, b, c, d, cminusb;
if (delsamps < 1.00001f) delsamps = 1.00001f;
if (delsamps > limit) delsamps = limit;
delsamps += fn;
fn = fn - 1.0f;
idelsamps = delsamps;
frac = delsamps - (t_sample)idelsamps;
bp = wp - idelsamps;
if (bp < vp + 4) bp += nsamps;
d = bp[-3];
c = bp[-2];
b = bp[-1];
a = bp[0];
cminusb = c-b;
*out++ = b + frac * (
cminusb - 0.1666667f * (1.-frac) * (
(d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
)
);
}
return (w+6);
}
static void sigvd_dsp(t_sigvd *x, t_signal **sp)
{
t_sigdelwrite *delwriter =
(t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
x->x_sr = sp[0]->s_sr * 0.001;
if (delwriter)
{
sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
0 : delwriter->x_vecsize);
dsp_add(sigvd_perform, 5,
sp[0]->s_vec, sp[1]->s_vec,
&delwriter->x_cspace, x, sp[0]->s_n);
}
else error("vd~: %s: no such delwrite~",x->x_sym->s_name);
}
static void sigvd_setup(void)
{
sigvd_class = class_new(gensym("vd~"), (t_newmethod)sigvd_new, 0,
sizeof(t_sigvd), 0, A_DEFSYM, 0);
class_addmethod(sigvd_class, (t_method)sigvd_dsp, gensym("dsp"), 0);
CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, x_f);
}
/* ----------------------- global setup routine ---------------- */
void d_delay_setup(void)
{
sigdelwrite_setup();
sigdelread_setup();
sigvd_setup();
}
......@@ -717,6 +717,8 @@ void canvas_map(t_canvas *x, t_floatarg f)
bug("canvas_map");
canvas_vis(x, 1);
}
else if (x->gl_mapped == 0)
canvas_vis(x, 1);
/* if parent has editor enabled and we're a sub-patch,
(but not an abstraction) match its edit mode to that
......@@ -741,8 +743,9 @@ void canvas_map(t_canvas *x, t_floatarg f)
for (y = x->gl_list; y; y = y->g_next)
gobj_vis(y, x, 1);
for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
gobj_select(sel->sel_what, x, 1);
if (x->gl_editor && x->gl_editor->e_selection)
for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
gobj_select(sel->sel_what, x, 1);
x->gl_mapped = 1;
canvas_drawlines(x);
if (x->gl_isgraph && x->gl_goprect)
......@@ -764,6 +767,7 @@ void canvas_map(t_canvas *x, t_floatarg f)
void canvas_redraw(t_canvas *x)
{
//fprintf(stderr,"canvas_redraw\n");
if (glist_isvisible(x))
{
canvas_map(x, 0);
......@@ -771,8 +775,9 @@ void canvas_redraw(t_canvas *x)
/* now re-highlight our selection */
t_selection *y;
for (y = x->gl_editor->e_selection; y; y = y->sel_next)
gobj_select(y->sel_what, x, 1);
if (x->gl_editor && x->gl_editor->e_selection)
for (y = x->gl_editor->e_selection; y; y = y->sel_next)
gobj_select(y->sel_what, x, 1);
}
}
......
This diff is collapsed.
......@@ -39,6 +39,7 @@ static void canvas_mouseup_gop(t_canvas *x, t_gobj *g);
static void canvas_done_popup(t_canvas *x, t_float which, t_float xpos, t_float ypos);
static void canvas_doarrange(t_canvas *x, t_float which, t_gobj *oldy, t_gobj *oldy_prev, t_gobj *oldy_next);
static void canvas_paste_xyoffset(t_canvas *x);
void canvas_setgraph(t_glist *x, int flag, int nogoprect);
// jsarlo
static char canvas_cnct_inlet_tag[4096];
......@@ -1112,7 +1113,7 @@ static void canvas_undo_arrange(t_canvas *x, void *z, int action)
t_gobj *oldy_prev=NULL, *oldy_next=NULL;
// if there is an object before ours (in other words our index is > 0
// if there is an object before ours (in other words our index is > 0)
if (glist_getindex(x,y))
oldy_prev = glist_nth(x, buf->u_previndex - 1);
......@@ -1133,6 +1134,188 @@ void canvas_arrange_setundo(t_canvas *x, t_gobj *obj, int newindex)
canvas_setundo(x, canvas_undo_arrange, canvas_undo_set_arrange(x, obj, newindex), "arrange");
}
/* --------- 7. apply on canvas ----------- */
typedef struct _undo_canvas_properties
{
int gl_pixwidth; /* width in pixels (on parent, if a graph) */
int gl_pixheight;
t_float gl_x1; /* bounding rectangle in our own coordinates */
t_float gl_y1;
t_float gl_x2;
t_float gl_y2;
int gl_screenx1; /* screen coordinates when toplevel */
int gl_screeny1;
int gl_screenx2;
int gl_screeny2;
int gl_xmargin; /* origin for GOP rectangle */
int gl_ymargin;
unsigned int gl_goprect:1; /* draw rectangle for graph-on-parent */
unsigned int gl_isgraph:1; /* show as graph on parent */
unsigned int gl_hidetext:1; /* hide object-name + args when doing graph on parent */
} t_undo_canvas_properties;
t_undo_canvas_properties *global_buf; /* we need this to avoid redundant undo creation when pressing apply and then ok in the canvas properties menu */
static void *canvas_undo_set_canvas(t_canvas *x)
{
//t_undo_canvas_properties *buf;
/* enable editor (in case it is disabled) and select the object we are working on */
if (!x->gl_edit)
canvas_editmode(x, 1);
if (global_buf == NULL) {
global_buf = (t_undo_canvas_properties *)getbytes(sizeof(*global_buf));
//fprintf(stderr,"creating a new buffer for canvas properties\n");
}
/*if (
global_buf->gl_pixwidth != x->gl_pixwidth ||
global_buf->gl_pixheight != x->gl_pixheight ||
global_buf->gl_x1 != x->gl_x1 ||
global_buf->gl_y1 != x->gl_y1 ||
global_buf->gl_x2 != x->gl_x2 ||
global_buf->gl_y2 != x->gl_y2 ||
global_buf->gl_screenx1 != x->gl_screenx1 ||
global_buf->gl_screeny1 != x->gl_screeny1 ||
global_buf->gl_screenx2 != x->gl_screenx2 ||
global_buf->gl_screeny2 != x->gl_screeny2 ||
global_buf->gl_xmargin != x->gl_xmargin ||
global_buf->gl_ymargin != x->gl_ymargin ||
global_buf->gl_goprect != x->gl_goprect ||
global_buf->gl_isgraph != x->gl_isgraph ||
global_buf->gl_hidetext != x->gl_hidetext)
{*/
//fprintf(stderr,"changing values\n");
global_buf->gl_pixwidth = x->gl_pixwidth;
global_buf->gl_pixheight = x->gl_pixheight;
global_buf->gl_x1 = x->gl_x1;
global_buf->gl_y1 = x->gl_y1;
global_buf->gl_x2 = x->gl_x2;
global_buf->gl_y2 = x->gl_y2;
global_buf->gl_screenx1 = x->gl_screenx1;
global_buf->gl_screeny1 = x->gl_screeny1;
global_buf->gl_screenx2 = x->gl_screenx2;
global_buf->gl_screeny2 = x->gl_screeny2;
global_buf->gl_xmargin = x->gl_xmargin;
global_buf->gl_ymargin = x->gl_ymargin;
global_buf->gl_goprect = x->gl_goprect;
global_buf->gl_isgraph = x->gl_isgraph;
global_buf->gl_hidetext = x->gl_hidetext;
//}
return (global_buf);
}
extern int gfxstub_haveproperties(void *key);
static void canvas_undo_canvas_apply(t_canvas *x, void *z, int action)
{
t_undo_canvas_properties *buf = z;
t_undo_canvas_properties *tmp;
if (!x->gl_edit)
canvas_editmode(x, 1);
if (action == UNDO_UNDO || action == UNDO_REDO)
{
//close properties window first
t_int properties = gfxstub_haveproperties((void *)x);
if (properties) {
//fprintf(stderr,"have it\n");
sys_vgui("destroy .gfxstub%lx\n", properties);
}
//create a temporary data holder
tmp = (t_undo_canvas_properties *)getbytes(sizeof(*tmp));
//store current canvas values into temporary data holder
tmp->gl_pixwidth = x->gl_pixwidth;
tmp->gl_pixheight = x->gl_pixheight;
tmp->gl_x1 = x->gl_x1;
tmp->gl_y1 = x->gl_y1;
tmp->gl_x2 = x->gl_x2;
tmp->gl_y2 = x->gl_y2;
tmp->gl_screenx1 = x->gl_screenx1;
tmp->gl_screeny1 = x->gl_screeny1;
tmp->gl_screenx2 = x->gl_screenx2;
tmp->gl_screeny2 = x->gl_screeny2;
tmp->gl_xmargin = x->gl_xmargin;
tmp->gl_ymargin = x->gl_ymargin;
tmp->gl_goprect = x->gl_goprect;
tmp->gl_isgraph = x->gl_isgraph;
tmp->gl_hidetext = x->gl_hidetext;
//change canvas values with the ones from the undo buffer
x->gl_pixwidth = buf->gl_pixwidth;
x->gl_pixheight = buf->gl_pixheight;
x->gl_x1 = buf->gl_x1;
x->gl_y1 = buf->gl_y1;
x->gl_x2 = buf->gl_x2;
x->gl_y2 = buf->gl_y2;
x->gl_screenx1 = buf->gl_screenx1;
x->gl_screeny1 = buf->gl_screeny1;
x->gl_screenx2 = buf->gl_screenx2;
x->gl_screeny2 = buf->gl_screeny2;
x->gl_xmargin = buf->gl_xmargin;
x->gl_ymargin = buf->gl_ymargin;
x->gl_goprect = buf->gl_goprect;
x->gl_isgraph = buf->gl_isgraph;
x->gl_hidetext = buf->gl_hidetext;
//copy data values from the temporary data to the undo buffer
buf->gl_pixwidth = tmp->gl_pixwidth;
buf->gl_pixheight = tmp->gl_pixheight;
buf->gl_x1 = tmp->gl_x1;
buf->gl_y1 = tmp->gl_y1;
buf->gl_x2 = tmp->gl_x2;
buf->gl_y2 = tmp->gl_y2;
buf->gl_screenx1 = tmp->gl_screenx1;
buf->gl_screeny1 = tmp->gl_screeny1;
buf->gl_screenx2 = tmp->gl_screenx2;
buf->gl_screeny2 = tmp->gl_screeny2;
buf->gl_xmargin = tmp->gl_xmargin;
buf->gl_ymargin = tmp->gl_ymargin;
buf->gl_goprect = tmp->gl_goprect;
buf->gl_isgraph = tmp->gl_isgraph;
buf->gl_hidetext = tmp->gl_hidetext;
//delete temporary data holder
t_freebytes(tmp, sizeof(*tmp));
//redraw
canvas_setgraph(x, x->gl_isgraph, 0);
canvas_dirty(x, 1);
if (x->gl_havewindow) {
canvas_redraw(x);
}
if (x->gl_owner && glist_isvisible(x->gl_owner))
{
//fprintf(stderr,"we got gop\n");
glist_noselect(x);
gobj_vis(&x->gl_gobj, x->gl_owner, 0);
gobj_vis(&x->gl_gobj, x->gl_owner, 1);
canvas_redraw(x->gl_owner);
}
//update scrollbars when GOP potentially exceeds window size
t_canvas *canvas=(t_canvas *)glist_getcanvas(x);
//if gop is being disabled go one level up
if (!x->gl_isgraph) canvas=canvas->gl_owner;
sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", (t_int)canvas);
}
else if (action == UNDO_FREE)
{
t_freebytes(buf, sizeof(*buf));
}
}
void canvas_canvas_setundo(t_canvas *x)
{
canvas_setundo(x, canvas_undo_canvas_apply, canvas_undo_set_canvas(x), "apply");
}
/* ------------------------ event handling ------------------------ */
......@@ -1324,7 +1507,7 @@ void canvas_vis(t_canvas *x, t_floatarg f)
{
//fprintf(stderr,"new window\n");
canvas_create_editor(x);
sys_vgui("pdtk_canvas_new .x%lx %d %d +%d+%d %d\n", x,
sys_vgui("catch {pdtk_canvas_new .x%lx %d %d +%d+%d %d}\n", x,
(int)(x->gl_screenx2 - x->gl_screenx1),
(int)(x->gl_screeny2 - x->gl_screeny1),
(int)(x->gl_screenx1), (int)(x->gl_screeny1),
......@@ -1511,13 +1694,14 @@ void canvas_properties(t_glist *x)
static void canvas_donecanvasdialog(t_glist *x,
t_symbol *s, int argc, t_atom *argv)
{
/* have to figure out how the parent window is stored
in the glist, also how to deal with abstractions,
so until that happens...
for the time being we only accept undo/redos that
apply to objects on the parent window (e.g. GOPs) */
if (glist_getcanvas(x) != x && !canvas_isabstraction(x))
/* parent windows are treated differently than applies to individual objects */
if (glist_getcanvas(x) != x && !canvas_isabstraction(x)) {
canvas_apply_setundo(glist_getcanvas(x), (t_gobj *)x);
}
else {
canvas_canvas_setundo(x);
//fprintf(stderr,"canvas_apply_undo\n");
}
t_float xperpix, yperpix, x1, y1, x2, y2, xpix, ypix, xmargin, ymargin;
int graphme, redraw = 0;
......@@ -1533,7 +1717,7 @@ static void canvas_donecanvasdialog(t_glist *x,
ypix = atom_getfloatarg(8, argc, argv);
xmargin = atom_getfloatarg(9, argc, argv);
ymargin = atom_getfloatarg(10, argc, argv);
x->gl_pixwidth = xpix;
x->gl_pixheight = ypix;
x->gl_xmargin = xmargin;
......@@ -1585,7 +1769,7 @@ static void canvas_donecanvasdialog(t_glist *x,
if (x->gl_havewindow) {
canvas_redraw(x);
}
else if (glist_isvisible(x->gl_owner))
else if (x->gl_owner && glist_isvisible(x->gl_owner))
{
glist_noselect(x);
gobj_vis(&x->gl_gobj, x->gl_owner, 0);
......@@ -1594,9 +1778,9 @@ static void canvas_donecanvasdialog(t_glist *x,
}
//ico@bukvic.net 100518 update scrollbars when GOP potentially exceeds window size
t_canvas *canvas=(t_canvas *)glist_getcanvas(x);
//if gop is being disabled go one level up
if (!graphme) canvas=canvas->gl_owner;
sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", (long unsigned int)canvas);
//if gop is being disabled go one level up (if u can)
if (!graphme && canvas->gl_owner) canvas=canvas->gl_owner;
sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", (t_int)canvas);
}
/* called by undo/redo arrange and done_canvas_popup. only done_canvas_popup
......