home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
x
/
volume19
/
xephem
/
part18
/
skyviewmenu.c.3
< prev
Wrap
Text File
|
1993-05-15
|
21KB
|
827 lines
} else {
label = (pu.op->o_flags ^= OBJF_LABEL) & OBJF_LABEL;
if (label) {
sv_getcircle (&w, &h, &r, &xb, &yb);
(void) sv_dbobjloc (pu.op, r, &x, &y);
name = pu.op->o_name;
}
}
if (label) {
/* label is being turned on so draw it */
Display *dsp = XtDisplay(svda_w);
Window win = sv_pm;
GC gc;
x += xb;
y += yb;
obj_pickgc (pu.op, svda_w, &gc);
draw_label (dsp, win, gc, name, x, y);
sv_copy_sky();
} else {
/* label is being turned off so redraw */
sv_all (mm_get_now(), 1);
}
}
/* remove trails no longer wanted. */
static void
tobj_rmoff()
{
TrailObj **topp; /* address to be changed if we decide to
* remove *topp
*/
TrailObj *top; /* handy *topp */
for (topp = &trailobj; (top = *topp) != NULL; ) {
if (top->on) {
topp = &top->ntop;
} else {
*topp = top->ntop;
XtFree ((char *)top);
}
}
}
/* remove the trailobj list that contains the given pointer.
* we have to search each trail list to find the one with this pointer.
* it might be the one on TrailObj itself or one of the older ones on
* the TSky list.
*/
static void
tobj_rmobj (op)
Obj *op;
{
TrailObj **topp; /* address to be changed if we decide to
* remove *topp
*/
TrailObj *top; /* handy *topp */
for (topp = &trailobj; (top = *topp) != NULL; ) {
int i;
if (top->op == op)
goto out;
for (i = 0; i < top->nsky; i++)
if (&top->sky[i].o == op)
goto out;
topp = &top->ntop;
}
out:
if (!top)
return; /* oh well */
*topp = top->ntop;
XtFree ((char *)top);
}
/* add a new empty entry to the trailobj list for db object op.
* return a pointer to the new TrailObj.
*/
static TrailObj *
tobj_addobj (op)
Obj *op;
{
TrailObj *top;
/* don't forget there is inherently room for one TSky in a TrailObj */
top = (TrailObj *)
XtMalloc (sizeof(TrailObj) + (TRAILCHUNKS-1)*sizeof(TSky));
top->nskymem = TRAILCHUNKS; /* there is room for TRAILCHUNKS TSkys .. */
top->nsky = 0; /* though none are in use in our new one */
top->op = op;
top->on = 1;
/* link directly off trailobj -- order is unimportant */
top->ntop = trailobj;
trailobj = top;
return (top);
}
/* increase the number of Sky's top can hold.
* since we may have to move top to do it, return the new pointer.
*/
static TrailObj *
tobj_growsky (top)
TrailObj *top;
{
TrailObj *ltop;
TrailObj *newtop;
int newn;
/* set ltop to the TrailObj in the list just before top */
if (trailobj == top)
ltop = NULL;
else {
for (ltop=trailobj; ltop; ltop=ltop->ntop)
if (ltop->ntop == top)
break;
if (!ltop) {
printf ("tobj_growsky(): top not found!\n");
exit (1);
}
}
/* don't forget there is already one TSky within a TrailObj. */
newn = top->nskymem + TRAILCHUNKS;
newtop = (TrailObj *) XtRealloc ((char *)top,
sizeof(TrailObj) + (newn-1)*sizeof(TSky));
if (ltop)
ltop->ntop = newtop;
else
trailobj = newtop;
newtop->nskymem = newn;
return (newtop);
}
/* empty the trailobj list and reclaim all space.
*/
static void
tobj_reset()
{
TrailObj *top, *ntop;
for (top = trailobj; top; top = ntop) {
ntop = top->ntop;
XtFree ((char *)top);
}
trailobj = NULL;
}
/* find the TrailObj that contains op */
static TrailObj *
tobj_find (op)
Obj *op;
{
TrailObj *top;
for (top = trailobj; top; top = top->ntop) {
int i;
if (top->op == op)
return (top);
for (i = 0; i < top->nsky; i++)
if (&top->sky[i].o == op)
return (top);
}
return (NULL);
}
/* add an Obj to the given trailobj, top.
* mark it as being valid as of jd (which is really an mjd).
* these are maintained in increasing order of time, ie, the first is the
* earliest. we take care not to add one for an identical time already in
* the list. since we might have to move top to grow it, we return a (possibly
* different) pointer.
*/
static TrailObj *
tobj_addsky (top, jd, op)
TrailObj *top;
double jd;
Obj *op;
{
int i;
/* make sure there is room for one more */
if (top->nsky == top->nskymem)
top = tobj_growsky (top);
/* add op to top->sky in ascending time order.
* exit loop with i as the index of the cell to use.
*/
for (i = top->nsky; i > 0; --i)
if (top->sky[i-1].ts_mjd < jd)
break;
else if (top->sky[i-1].ts_mjd == jd)
return (top); /* don't add a dup */
else
top->sky[i] = top->sky[i-1];
top->sky[i].flags = 0;
top->sky[i].ts_mjd = jd;
top->sky[i].o = *op;
top->nsky++;
return (top);
}
/* display everything in the trailobj list that is marked on onto sv_pm
* clipped to a circle of radius r, offset by xb and yb borders.
*/
static void
tobj_display_all(r, xb, yb)
unsigned r, xb, yb;
{
Display *dsp = XtDisplay(svda_w);
Window win = sv_pm;
TrailObj *top;
for (top = trailobj; top; top = top->ntop) {
int x1, y1, x2, y2;
int before;
Obj *op;
GC gc;
int i;
if (!top->on)
continue;
obj_pickgc(top->op, svda_w, &gc);
before = 0;
for (i = 0; i < top->nsky; i++) {
op = &top->sky[i].o;
if (sv_trailobjloc (&top->sky[i], r, &x2, &y2)) {
sv_draw_obj (dsp, win, gc, op, x2+xb, y2+yb,
magdiam(op->s_mag/MAGSCALE), justdots);
if (all_labels || (top->sky[i].flags & OBJF_LABEL))
draw_label (dsp, win, gc, op->o_name, x2+xb, y2+yb);
}
if (before++) {
int sx1, sy1, sx2, sy2;
if (lc(0,0,r*2,x1,y1,x2,y2,&sx1,&sy1,&sx2,&sy2) == 0)
XDrawLine (dsp, win, gc, sx1+xb, sy1+yb, sx2+xb,sy2+yb);
}
x1 = x2;
y1 = y2;
}
}
sv_draw_obj (dsp, win, (GC)0, NULL, 0, 0, 0, 0); /* flush */
}
/* determine if the given object is visible and within a circle of radius r
* pixels. if so, return 1 and compute the location in *xp/*yp, else return 0.
* N.B. only call this for bona fide db objects -- *not* for objects in the
* TrailObj lists -- it will destroy their history.
*/
static
sv_dbobjloc (op, r, xp, yp)
Obj *op;
int r;
int *xp, *yp;
{
double altdec, azra;
if (!sv_precheck(op))
return (0);
/* remaining things need accurate s_* fields */
db_update(op);
if (aa_mode && op->s_alt < 0.0)
return(0); /* it's below horizon and we're in alt-az mode */
if (op->s_mag/MAGSCALE > fmag || op->s_mag/MAGSCALE < bmag)
return(0); /* it's not within mag range after all */
altdec = aa_mode ? op->s_alt : op->s_dec;
azra = aa_mode ? op->s_az : op->s_ra;
if (!sv_loc (r, altdec, azra, xp, yp))
return(0); /* it's outside the fov after all */
return (1); /* yup, really within r */
}
/* given a TSky find its location in a circle of radius r, all in pixels.
* return 1 if the resulting x/y is in fact within the circle, else 0 if it is
* outside or otherwise should not be shown now (but return the x/y anyway).
* N.B. we take care to not change the tsp->o in any way.
*/
static
sv_trailobjloc (tsp, r, xp, yp)
TSky *tsp;
int r;
int *xp, *yp;
{
Obj *op = &tsp->o;
double altdec, azra;
int infov;
altdec = aa_mode ? op->s_alt : op->s_dec;
azra = aa_mode ? op->s_az : op->s_ra;
infov = sv_loc (r, altdec, azra, xp, yp);
return (infov && (!aa_mode || op->s_alt >= 0.0) && sv_precheck(op)?1:0);
}
/* do as much as possible to pre-check whether op is on screen now
* WITHOUT computing it's actual coordinates. put another way, we are not to
* use and s_* fields in these tests.
* return 0 if we know it's definitely not on screen, or 1 if it might be.
*/
static
sv_precheck (op)
Obj *op;
{
if (op->type == UNDEFOBJ)
return(0);
if (!svf_filter_ok(op) || !sv_bright_ok(op) || !sv_infov(op))
return(0); /* wrong type, wrong brightness or outside for sure */
return (1);
}
/* return 1 if db object is ever possibly within the fmag/bmag range; else 0.
*/
static
sv_bright_ok(op)
Obj *op;
{
switch (op->type) {
case PLANET:
/* always go for the planets for now but ..
* TODO: work up a table of extreme planet magnitudes.
*/
return (1);
/* break; */
case HYPERBOLIC: return (1); /* and interlopers */
case PARABOLIC: return (1);
case ELLIPTICAL: {
double mag; /* magnitude */
double per, aph; /* perihelion and aphelion distance */
per = op->e_a*(1.0 - op->e_e);
aph = op->e_a*(1.0 + op->e_e);
if (per <= 1.1 && aph >= 0.9)
return (1); /* might be blazing in the back yard some day */
if (op->e_mag.whichm == MAG_HG)
mag = op->e_mag.m1 + 5*log10(per*fabs(per-1.0));
else
gk_mag(op->e_mag.m1, op->e_mag.m2,
per, fabs(per-1.0), &mag);
return (mag <= fmag && mag >= bmag);
/* break; */
}
case FIXED:
return (op->f_mag/MAGSCALE <= fmag && op->f_mag/MAGSCALE >= bmag);
/* break; */
default:
printf ("sv_bright_ok(): bad type: %d\n", op->type);
exit (1);
return (0); /* for lint */
}
}
/* return 1 if the object can potentially be within the current sv_fov, else 0.
* N.B. this is meant to be cheap - we only do fixed objects and we don't
* precess. most importantly, we don't use any s_* fields.
*/
static
sv_infov (op)
Obj *op;
{
#define DELEP 100 /* maximum epoch difference we dare go without
* precessing, years
*/
#define MARGIN degrad(3.0) /* border around fov still considered "in"
* in spite of having not precessed.
*/
double ra0, dec0; /* ra/dec of our center of view */
double a, sa, ca; /* angle from viewpoint to pole */
double b, sb, cb; /* angle from object to pole */
double c, cc; /* diff of polar angles of obj and viewpoint */
double d; /* angular separation of object and viewpoint */
Now *np = mm_get_now();
if (op->type != FIXED)
return (1);
if (fabs (mjd - op->f_epoch) > DELEP)
return (1);
if (aa_mode) {
/* TODO: cache this -- it's the same for each obj! */
double ha, lst;
aa_hadec (lat, sv_altdec, sv_azra, &ha, &dec0);
now_lst (np, &lst);
ra0 = hrrad(lst) - ha;
range (&ra0, 2*PI);
} else {
ra0 = sv_azra;
dec0 = sv_altdec;
}
a = PI/2 - dec0;
sa = sin(a);
ca = cos(a);
b = PI/2 - op->f_dec;
sb = sin(b);
cb = cos(b);
c = ra0 - op->f_RA;
cc = cos(c);
d = acos(ca*cb + sa*sb*cc);
return (d < sv_fov/2 + MARGIN);
}
/* compute x/y loc of a point at azra/altdec on a circle of radius rad pixels
* as viewed from sv_azra/sv_altdec with sv_fov.
* return 1 if fits on screen, else 0 (but still return x/y).
*/
static
sv_loc (rad, altdec, azra, xp, yp)
int rad; /* radius of target display, pixels */
double altdec; /* angle up from spherical equator, such as alt or dec; rad */
double azra; /* angle around spherical pole, such as az or ra; rad */
int *xp, *yp; /* return X coords within circle */
{
#define LOCEPS (1e-5) /* an angle too small to see on screen, rads */
double a,sa,ca; /* angle from viewpoint to pole */
double b,sb,cb; /* angle from object to pole */
double c,sc,cc; /* difference in polar angles of obj and viewpoint */
double d,sd,cd; /* angular separation of object and viewpoint */
double r; /* proportion of d to desired field of view */
double se, ce; /* angle between (viewpoint,pole) and (viewpoint,obj) */
a = PI/2 - sv_altdec;
sa = sin(a);
ca = cos(a);
b = PI/2 - altdec;
sb = sin(b);
cb = cos(b);
if (aa_mode)
c = azra - sv_azra;
else
c = sv_azra - azra;
cc = cos(c);
d = acos(ca*cb + sa*sb*cc);
if (d < LOCEPS) {
*xp = *yp = rad;
return (1);
}
r = d/(sv_fov/2.0);
sc = sin(c);
sd = sin(d);
se = sc*sb/sd;
*xp = rad*(1 + r*se) + 0.5;
if (a < LOCEPS) {
/* as viewpoint approaches N pole, e approaches PI - c */
ce = -cc;
} else if (a > PI - LOCEPS) {
/* as viewpoint approaches S pole, e approaches c */
ce = cc;
} else {
cd = cos(d);
ce = (cb - cd*ca)/(sd*sa);
}
*yp = rad*(1 - r*ce) + 0.5;
return (r >= 1.0 ? 0 : 1);
}
/* compute azra/altdec loc of a point at x/y on a circle of radius rad pixels
* as viewed from sv_azra/sv_altdec with sv_fov.
* return 1 if x/y are within the circle, else 0.
*/
static
sv_unloc (rad, x, y, altdecp, azrap)
int rad; /* radius of target display, pixels */
int x, y; /* X coords within circle */
double *altdecp;/* angle up from spherical equator, such as alt or dec; rad */
double *azrap; /* angle around spherical pole, such as az or ra; rad */
{
#define UNLOCEPS (1e-4) /* sufficiently close to pole to not know az/ra; rads */
double a,sa,ca; /* angle from viewpoint to pole */
double r; /* distance from center to object, pixels */
double d,sd,cd; /* angular separation of object and viewpoint */
double e,se,ce; /* angle between (viewpoint,pole) and (viewpoint,obj) */
double b,sb,cb; /* angle from object to pole */
double c,sc,cc; /* difference in polar angles of obj and viewpoint */
if (x == rad && y == rad) {
/* at the center -- avoids cases where r == 0 */
*altdecp = sv_altdec;
*azrap = sv_azra;
return (1);
}
a = PI/2 - sv_altdec;
sa = sin(a);
ca = cos(a);
r = sqrt ((double)((x-rad)*(x-rad) + (y-rad)*(y-rad)));
if (r > rad)
return(0); /* outside the circle */
d = r/rad*(sv_fov/2.0);
sd = sin(d);
cd = cos(d);
ce = (rad - y)/r;
se = (x - rad)/r;
cb = ca*cd + sa*sd*ce;
b = acos(cb);
*altdecp = PI/2 - b;
/* find c, the polar angle between viewpoint and object */
if (a < UNLOCEPS) {
/* as viewpoint approaches N pole, c approaches PI - e */
c = acos(-ce);
} else if (a > PI - UNLOCEPS) {
/* as viewpoint approaches S pole, c approaches e */
c = acos(ce);
} else if (b < UNLOCEPS || b > PI - UNLOCEPS) {
/* as object approaches either pole, c becomes arbitary */
c = 0.0;
} else {
sb = sin(b);
cc = (cd - ca*cb)/(sa*sb);
if (cc < -1.0) cc = -1.0; /* heh, it happens ... */
if (cc > 1.0) cc = 1.0; /* heh, it happens ... */
c = acos (cc); /* 0 .. PI; next step checks if c
* should be > PI
*/
}
if (se < 0.0) /* if e > PI */
c = PI + (PI - c); /* so is c */
if (aa_mode)
*azrap = sv_azra + c;
else
*azrap = sv_azra - c;
range (azrap, 2*PI);
return (1);
}
/* draw a nice grid on a circle of radius r, x and y borders xb and yb.
*/
static void
draw_grid(dsp, win, gc, r, xb, yb)
Display *dsp;
Window win;
GC gc;
unsigned int r;
unsigned int xb, yb;
{
double vticks[NGRID], hticks[NGRID];
double vmin, vmax, hmin, hmax;
XSegment xsegments[NGRID*NSEGS], *xs;
char msg[64];
int nvt, nht;
int i, j;
int pole;
/* set vertical min and max, and detect whether pole is within fov.
* since display is in degrees, use that unit for finding ticks.
*/
pole = 0;
vmin = sv_altdec-sv_fov/2;
if (vmin < 0 && aa_mode)
vmin = 0.0;
if (vmin <= -PI/2) {
/* clamp at pole */
vmin = -PI/2;
pole = 1;
}
vmax = sv_altdec+sv_fov/2;
if (vmax >= PI/2) {
/* clamp at pole */
vmax = PI/2;
pole = 1;
}
vmin = raddeg(vmin);
vmax = raddeg(vmax);
/* set horizontal min and max.
* if pole is visible, we go all the way around.
* else compute spherical angle spanned by fov "del" from pole.
* again, compute ticks in the units we display in.
*/
if (pole) {
/* pole is visible */
hmin = 0.0;
hmax = 2*PI;
} else {
double del = PI/2 - fabs(sv_altdec);
double a= acos((cos(sv_fov) - cos(del)*cos(del))/sin(del)/sin(del));
hmin = sv_azra-a/2;
hmax = sv_azra+a/2;
}
hmin = aa_mode ? raddeg(hmin) : radhr(hmin);
hmax = aa_mode ? raddeg(hmax) : radhr(hmax);
/* find tick marks.
* generally get less than half the max, so insure it to be consistent.
* N.B. remember that tickmarks() can return up to 2 more than asked.
*/
nvt = tickmarks(vmin, vmax, NGRID-2, vticks);
nht = tickmarks(hmin, hmax, NGRID-2, hticks);
/* report the spacing */
(void) sprintf (msg, "%s: %g Degs", aa_mode ? "Alt" : "Dec",
(vticks[nvt-1]-vticks[0])/(nvt-1));
f_showit (vgrid_w, msg);
(void) sprintf (msg, " %s: %g %s", aa_mode ? "Az" : "RA",
(hticks[nht-1]-hticks[0])/(nht-1), aa_mode ? "Degs" : "Hrs");
f_showit (hgrid_w, msg);
/* convert back to rads */
for (i = 0; i < nvt; i++)
vticks[i] = degrad(vticks[i]);
for (i = 0; i < nht; i++)
hticks[i] = aa_mode ? degrad(hticks[i]) : hrrad(hticks[i]);
/* for each horizontal tick mark
* for each vertical tick mark
* compute coord on screen
* if we've at least 2 pts now
* connect the points with what is visible within the circle.
*/
for (i = 0; i < nht; i += 1) {
double h = hticks[i];
int before = 0;
int vis1, vis2;
int x1, y1, x2, y2;
xs = xsegments;
for (j = 0; j < nvt; j++) {
double v = vticks[j];
vis2 = sv_loc(r, v, h, &x2, &y2);
if (before++ && (vis1 || vis2)) {
int sx1, sy1, sx2, sy2;
if (lc(0,0,r*2,x1,y1,x2,y2,&sx1,&sy1,&sx2,&sy2) == 0) {
xs->x1 = sx1+xb; xs->y1 = sy1+yb;
xs->x2 = sx2+xb; xs->y2 = sy2+yb;
xs++;
}
}
x1 = x2;
y1 = y2;
vis1 = vis2;
}
XDrawSegments (dsp, win, gc, xsegments, xs - xsegments);
}
/* for each vertical tick mark
* for each horizontal tick mark
* compute coord on screen
* if we've at least 2 pts now
* connect the points with what is visible within the circle.
* (break into smaller pieces because these lines tend to curve)
*/
for (i = 0; i < nvt; i+=1) {
double v = vticks[i];
double h1;
int before = 0;
int vis1, vis2;
int x1, y1, x2, y2;
xs = xsegments;
for (j = 0; j < nht; j++) {
double h = hticks[j];
vis2 = sv_loc(r, v, h, &x2, &y2);
if (before++ && (vis1 || vis2)) {
/* last point is at (x1,y1) == (h1,v);
* this point is at (x2,y2) == (h, v);
* connect with NSEGS segments.
*/
int sx1, sy1, sx2, sy2;
int xt, yt;
int vist, k;
for (k = 1; k <= NSEGS; k++) {
if (k == NSEGS) {
xt = x2;
yt = y2;
vist = vis2;
} else
vist = sv_loc(r, v, h1+k*(h-h1)/NSEGS, &xt, &yt);
if ((vis1 || vist) &&
lc(0,0,r*2,x1,y1,xt,yt,&sx1,&sy1,&sx2,&sy2)==0){
xs->x1 = sx1+xb; xs->y1 = sy1+yb;
xs->x2 = sx2+xb; xs->y2 = sy2+yb;
xs++;
}
x1 = xt;
y1 = yt;
vis1 = vist;
}
}
x1 = x2;
y1 = y2;
h1 = h;
vis1 = vis2;
}
XDrawSegments (dsp, win, gc, xsegments, xs - xsegments);
}
}
/* draw the ecliptic on a circle of radius r, x and y borders xb and yb.
* special thanks to Uwe Bonnes <bon@LTE.E-TECHNIK.uni-erlangen.de>
*/
static void
draw_ecliptic(dsp, win, gc, r, xb, yb)
Display *dsp;
Window win;
GC gc;
unsigned int r;
unsigned int xb, yb;
{
#define ECL_CACHE_SZ 100
XPoint point_cache[ECL_CACHE_SZ];
double elat0, elng0; /* ecliptic lat and long at center of fov */
double elngmin, elngmax;/* ecliptic long limits */
double ra, dec;
double elng;
double lst;
int ncache;
Now *np;
np = mm_get_now();
now_lst (np, &lst);
/* find ecliptic coords of center of view */
if (aa_mode) {
double ha0; /* local hour angle */
aa_hadec (lat, sv_altdec, sv_azra, &ha0, &dec);
ra = hrrad(lst) - ha0;
} else {
ra = sv_azra;
dec = sv_altdec;
}
eq_ecl (mjd, ra, dec, &elat0, &elng0);
/* no ecliptic visible if ecliptic latitude at center of view
* is not less than fov/2
*/
if (fabs(elat0) >= sv_fov/2.0)
return;
/* worst-case elong limits is center elong += half fov */
elngmin = elng0 - sv_fov/2.0;
elngmax = elng0 + sv_fov/2.0;
/* put a mark at every ECL_TICS pixels */
ncache = 0;
for (elng = elngmin; elng <= elngmax; elng += sv_fov/(2.0*r/ECL_TICS)) {
int x, y;
double altdec, azra;
/* convert longitude along the ecliptic to ra/dec */
ecl_eq (mjd, 0.0, elng, &azra, &altdec);
/* if in aa mode, we need it in alt/az */
if (aa_mode) {
hadec_aa (lat, hrrad(lst) - azra, altdec, &altdec, &azra);
refract (pressure, temp, altdec, &altdec);
}
/* if visible, display point */
if ((!aa_mode || altdec >= 0) && sv_loc (r, altdec, azra, &x, &y)) {
XPoint *xp = &point_cache[ncache++];
xp->x = x + xb;
xp->y = y + yb;
if (ncache == XtNumber(point_cache)) {
XDrawPoints (dsp,win,gc,point_cache,ncache,CoordModeOrigin);
ncache = 0;
}
}
}
if (ncache > 0)
XDrawPoints (dsp, win, gc, point_cache, ncache, CoordModeOrigin);
}
/* given the magnitude of an object, return its desired diameter, in pixels.
* N.B. we assume it is at least as bright as fmag.
*/
static
magdiam(m)
double m;
{
return (((int)(fmag-m)+3)/2);
}
/* make the general purpose sv_gc and learn the three colors.
*/
static void
sv_mk_gcs(dsp, win)
Display *dsp;
Window win;
{
XGCValues gcv;
unsigned gcm = 0;
get_something (svda_w, XmNforeground, (char *)&fg_p);
get_something (svda_w, XmNbackground, (char *)&sky_p);
get_something (svform_w, XmNbackground, (char *)&bg_p);
set_something (svda_w, XmNbackground, (char *)bg_p);
sv_gc = XCreateGC (dsp, win, gcm, &gcv);
}
/* draw a label for an object that is located at [x,y]
*/
static void
draw_label (dsp, win, gc, label, x, y)
Display *dsp;
Window win;
GC gc;
char label[];
int x, y;
{
XDrawString (dsp, win, gc, x+4, y-4, label, strlen(label));
}