============
+Changes since 3.05: * Oops, the "default-n" visual descriptor was broken;
+ it was always installing a colormap if the
+ `installColormap' preference was set, meaning that
+ `xearth', `xv' and friends were using the wrong
+ colors on 8-bit systems.
+ * Turned off HAVE_PING in `sonar', since it compiles
+ on some Linux systems, but not others of similar
+ vintage...
+Changes since 3.04: * Fixed an off-by-1 in `distort'.
+ * Added `sonar' hack.
+ * New version of `glplanet' (with stars.)
+ * Made all hacks exit when you type `q' or `ESC' at them,
+ and made them obey the WM_DELETE_WINDOW ClientMessage.
+ * Fixed a nonfatal buffer overrun in lament (note:
+ lament still doesn't work with MesaGL 3.0: it dies in
+ lambda_textured_triangle1(), which is Mesa's bug, not
+ mine.)
Changes since 3.03: * Added an `xscreensaver.spec' file, to make it easier
for other folks to generate RPMs.
* Made the password code work on HPUX in the situation
! a screen saver and locker for the X window system
! by Jamie Zawinski
!
-! version 3.04
-! 16-Nov-98
+! version 3.06
+! 22-Nov-98
!
! See "man xscreensaver" for more info. The latest version is always
! available at http://www.jwz.org/xscreensaver/
kumppa -root \n\
rd-bomb -root \n\
rd-bomb -root -speed 1 -size 0.1 \n\
+ sonar -root \n\
\
mono: rocks -root \n\
color: rocks -root -fg darksalmon \n\
kumppa -root \\n\
rd-bomb -root \\n\
rd-bomb -root -speed 1 -size 0.1 \\n\
+ sonar -root \\n\
\
mono: rocks -root \\n\
color: rocks -root -fg darksalmon \\n\
{
saver_info *si = ssi->global;
saver_preferences *p = &si->prefs;
- Bool install_cmap_p = (ssi->install_cmap_p || p->install_cmap_p);
+ Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
/* This resets the screensaver window as fully as possible, since there's
no way of knowing what some random client may have done to us in the
ssi->cmap = 0;
if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
+ /* It's not the default visual, so we have no choice but to install. */
install_cmap_p = True;
if (install_cmap_p)
got_it = !!new_v;
if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
+ /* It's not the default visual, so we have no choice but to install. */
install_cmap_p = True;
ssi->install_cmap_p = install_cmap_p;
.if n .sp 1
.if t .sp .5
..
-.TH XScreenSaver 1 "16-Nov-98 (3.04)" "X Version 11"
+.TH XScreenSaver 1 "22-Nov-98 (3.06)" "X Version 11"
.SH NAME
xscreensaver-command - control a running xscreensaver process
.SH SYNOPSIS
.if n .sp 1
.if t .sp .5
..
-.TH XScreenSaver 1 "16-Nov-98 (3.04)" "X Version 11"
+.TH XScreenSaver 1 "22-Nov-98 (3.06)" "X Version 11"
.SH NAME
xscreensaver-demo - interactively control the background xscreensaver daemon
.SH SYNOPSIS
destroy and recreate it on different
visuals. */
Colormap cmap; /* The colormap that goes with the window. */
- Bool install_cmap_p; /* whether we should use our own colormap.
- This can be overridden on a per-hack basis.
- */
+ Bool install_cmap_p; /* Whether this screen should have its own
+ colormap installed, for whichever of several
+ reasons. This is definitive (even a false
+ value here overrides prefs->install_cmap_p.)
+ */
Visual *current_visual; /* The visual of the window. */
Visual *default_visual; /* visual to use when none other specified */
int current_depth; /* How deep the visual (and the window) are. */
.if n .sp 1
.if t .sp .5
..
-.TH XScreenSaver 1 "16-Nov-98 (3.04)" "X Version 11"
+.TH XScreenSaver 1 "22-Nov-98 (3.06)" "X Version 11"
.SH NAME
xscreensaver - graphics hack and screen locker, launched when the user is idle
.SH SYNOPSIS
.BR mwm (1)
and
.BR olwm (1)
-window managers don't seem to have this problem. The race condition exists
-because X does not provide a way for an OverrideRedirect window to have its
-own colormap, short of grabbing the server (which is neither a good idea, nor
-really possible with the current design.) What happens is that, as soon as
-the screensaver installs its colormap, \fBtwm\fP responds to
-the \fBColormapNotify\fP event that is generated by re-instaling the default
-colormap. Apparently, \fBtwm\fP doesn't \fIalways\fP do this; it seems to do
-it regularly if the screensaver is activated from a menu item, but seems to
-not do it if the screensaver comes on of its own volition, or is activated
-from another console. Any thoughts on this problem are welcome...
+window managers don't have this problem. The race condition exists
+because X (really, ICCCM) does not provide a way for an OverrideRedirect
+window to have its own colormap, short of grabbing the server (which is
+neither a good idea, nor really possible with the current design.) What
+happens is that, as soon as xscreensaver installs its colormap, \fBtwm\fP
+responds to the resultant \fBColormapNotify\fP event by re-instaling the
+default colormap. Apparently, \fBtwm\fP doesn't \fIalways\fP do this; it
+seems to do it regularly if the screensaver is activated from a menu item,
+but seems to not do it if the screensaver comes on of its own volition, or
+is activated from another console.
+.RS 8
+.TP 4
+.B Attention, window manager authors!
+You should only call
+.BR XInstallColormap (3)
+in response to user events. That is, it is appropriate to install a colormap
+in response to \fBFocusIn\fP, \fBFocusOut\fP, \fBEnterNotify\fP,
+and \fBLeaveNotify\fP events; but it is not appropriate to call it in
+response to \fBColormapNotify\fP events. If you install colormaps in
+response to \fIapplication\fP actions as well as in response to \fIuser\fP
+actions, then you create the situation where it is impossible for
+override-redirect applications (such as xscreensaver) to display their
+windows in the proper colors.
+.RE
.TP 8
.B Colormap lossage: XV, XAnim, XEarth
Some programs don't operate properly on visuals other than the default one,
resource in the \fIConfiguration\fP section. When programs only work with
the default colormap, you need to use a syntax like this:
.EX
- default-n: xv -root image-1.gif -quit \\n\\
- default-n: xearth -nostars -wait 0 \\n\\
+ default-n: xv -root image-1.gif -quit \\n\\
+ default-n: xearth -nostars -wait 0 \\n\\
.EE
It would also work to turn off the \fBinstallColormap\fP option altogether,
but that would deny extra colors to those programs that \fIcan\fP take
rd-bomb.c coral.c mountain.c triangle.c lissie.c worm.c \
rotor.c ant.c xjack.c xlyap.c jigsaw.c xscreensaver-sgigl.c \
cynosure.c moire2.c flow.c epicycle.c interference.c \
- truchet.c bsod.c crystal.c discrete.c distort.c kumppa.c
+ truchet.c bsod.c crystal.c discrete.c distort.c kumppa.c \
+ sonar.c
OBJS = attraction.o blitspin.o bouboule.o braid.o bubbles.o \
bubbles-default.o decayscreen.o deco.o drift.o flag.o \
rd-bomb.o coral.o mountain.o triangle.o lissie.o worm.o \
rotor.o ant.o xjack.o xlyap.o jigsaw.o xscreensaver-sgigl.o \
cynosure.o moire2.o flow.o epicycle.o interference.o \
- truchet.o bsod.o crystal.o discrete.o distort.o kumppa.o
+ truchet.o bsod.o crystal.o discrete.o distort.o kumppa.o \
+ sonar.o
EXES = attraction blitspin bouboule braid bubbles decayscreen deco \
drift flag flame forest vines galaxy grav greynetic halo \
slip sphere spiral strange swirl xroger goop starfish munch \
fadeplot rd-bomb coral mountain triangle lissie worm rotor \
ant xjack xlyap jigsaw cynosure moire2 flow epicycle \
- interference truchet bsod crystal discrete distort kumppa
+ interference truchet bsod crystal discrete distort kumppa \
+ sonar
HACK_OBJS_1 = $(UTILS_BIN)/resources.o $(UTILS_BIN)/visual.o \
$(UTILS_BIN)/usleep.o $(UTILS_BIN)/yarandom.o @XMU_OBJS@
rocks.man rorschach.man sierpinski.man slidescreen.man \
slip.man sphere.man spiral.man strange.man swirl.man \
xroger.man goop.man starfish.man munch.man rd-bomb.man \
- xjack.man xlyap.man jigsaw.man epicycle.man bsod.man
+ xjack.man xlyap.man jigsaw.man epicycle.man bsod.man \
+ sonar.man
STAR = *
EXTRAS = README Makefile.in xlock_23.h .gdbinit \
vidwhacker \
kumppa: $(HACK_OBJS) kumppa.o
$(CC_HACK) -o $@ $(HACK_OBJS) kumppa.o $(HACK_LIBS)
+sonar: $(HACK_OBJS) sonar.o $(COL)
+ $(CC_HACK) -o $@ $(HACK_OBJS) sonar.o $(COL) $(HACK_LIBS)
+
# The rules for those hacks which follow the `xlockmore' API.
#
kumppa.o: $(UTILS_SRC)/colors.h
kumppa.o: $(UTILS_SRC)/grabscreen.h
kumppa.o: $(UTILS_SRC)/visual.h
+sonar.o: $(srcdir)/screenhack.h
+sonar.o: ../config.h
+sonar.o: $(UTILS_SRC)/yarandom.h
+sonar.o: $(UTILS_SRC)/usleep.h
+sonar.o: $(UTILS_SRC)/resources.h
+sonar.o: $(UTILS_SRC)/hsv.h
+sonar.o: $(UTILS_SRC)/colors.h
+sonar.o: $(UTILS_SRC)/grabscreen.h
+sonar.o: $(UTILS_SRC)/visual.h
-/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
+/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997, 1998
* Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
abort ();
}
- XSync (dpy, True);
+ XSync (dpy, False);
}
\f
while (1)
{
run_balls (dpy, window);
+ screenhack_handle_events (dpy);
if (delay) usleep (delay);
}
}
display (self);
XSync(dpy, False);
+ screenhack_handle_events (dpy);
}
static void
((xgwa.width-size)>>1)-1, ((xgwa.height-size)>>1)-1,
size+2, size+2);
*/
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
}
\f
while (1)
{
rotate ();
+ screenhack_handle_events (d);
if (delay2) usleep (delay2);
}
}
static Bool
bsod_sleep(Display *dpy, int seconds)
{
- XEvent event;
int q = seconds * 4;
- int mask = KeyPressMask|ButtonPressMask;
do
{
XSync(dpy, False);
- if (XCheckMaskEvent(dpy, mask, &event))
- {
- while (XCheckMaskEvent(dpy, mask, &event))
- ;
- return True;
- }
+ while (XPending (dpy))
+ {
+ XEvent event;
+ XNextEvent (dpy, &event);
+ if (event.xany.type == KeyPress)
+ {
+ KeySym keysym;
+ char c = 0;
+ XLookupString (&event.xkey, &c, 1, &keysym, 0);
+ if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+ return True;
+ }
+ screenhack_handle_event (dpy, &event);
+ }
+
if (q > 0)
{
q--;
if (delay < 3) delay = 3;
if (!get_boolean_resource ("root", "Boolean"))
- XSelectInput(dpy, window, KeyPressMask|ButtonPressMask);
+ {
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (dpy, window, &xgwa);
+ XSelectInput (dpy, window,
+ xgwa.your_event_mask | KeyPressMask | ButtonPressMask);
+ }
while (1)
{
if (loop > 100) j = -1;
if (loop > 200) exit(-1);
if (!did) continue;
- XSync (dpy, True);
+ XSync (dpy, False);
j = i;
loop = 0;
}
/* bubbles.c - frying pan / soft drink in a glass simulation */
-/*$Id: bubbles.c,v 1.15 1998/06/21 23:49:25 jwz Exp $*/
+/*$Id: bubbles.c,v 1.16 1998/11/19 07:25:01 jwz Exp $*/
/*
* Copyright (C) 1995-1996 James Macnicol
add_to_mesh(tmp);
insert_new_bubble(tmp);
- XSync (dpy, True);
+ XSync (dpy, False);
}
init_bubbles (dpy, window);
while (1) {
bubbles (dpy, window);
+ screenhack_handle_events (dpy);
if (delay)
usleep(delay);
}
$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SIERPINSKI.C
$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SLIDESCREEN.C
$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SLIP.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SONAR.C
$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SPHERE.C
$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SPIRAL.C
$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) STARFISH.C
$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SIERPINSKI.C
$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SLIDESCREEN.C
$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SLIP.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SONAR.C
$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SPHERE.C
$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SPIRAL.C
$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) STARFISH.C
XDrawPoints(dpy, window, draw_gc, pointbuf, npoints,
CoordModeOrigin);
npoints = 0;
- XSync(dpy, True);
+ XSync(dpy, False);
}
if (color) {
}
if( 0 == nwalkers ) {
- XSync(dpy, True);
+ XSync(dpy, False);
free(pointbuf);
return;
}
XDrawPoints(dpy, window, draw_gc, pointbuf, npoints,
CoordModeOrigin);
npoints = 0;
- XSync(dpy, True);
+ XSync(dpy, False);
}
+ screenhack_handle_events (dpy);
usleep(delay2);
}
}
while( 1 ) {
init_coral(dpy, window);
coral(dpy, window);
+ screenhack_handle_events (dpy);
if( delay ) sleep(delay);
erase_full_window(dpy, window);
}
}
paint();
XSync(dpy, False);
+ screenhack_handle_events (dpy);
if (delay)
usleep(delay);
}
for (i = 0; i < 100; i++)
decay1 (dpy, window);
XSync(dpy, False);
+ screenhack_handle_events (dpy);
if (delay) usleep (delay);
}
}
-/* xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1997, 1998 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
XFillRectangle(dpy, window, bgc, 0, 0, xgwa.width, xgwa.height);
deco (dpy, window, xgwa.colormap, fgc, bgc,
0, 0, xgwa.width, xgwa.height, 0);
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
if (!delay) continue;
if (!writable)
while (start - delay < time((time_t) 0))
{
rotate_colors (dpy, xgwa.colormap, colors, ncolors, 1);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
if (cycle_delay)
usleep (cycle_delay);
}
else {
int x = xy_coo[k].x + cx + (lx * rsq / dist);
int y = xy_coo[k].y + cy + (ly * rsq / dist);
- if (x < 0 || x > xgwa.width ||
- y < 0 || y > xgwa.height)
+ if (x < 0 || x >= xgwa.width ||
+ y < 0 || y >= xgwa.height)
XPutPixel( buffer_map, j, i, black_pixel );
else
XPutPixel( buffer_map, j, i,
draw(k);
}
- XSync(dpy, True);
+ XSync(dpy, False);
+ screenhack_handle_events (dpy);
if (delay) usleep(delay);
}
printf("re-mapped!\n");
unmapped = 0;
break;
+
+ default:
+ screenhack_handle_event(dpy, &e);
+ break;
}
/* If we're unmapped, don't return to the caller. This
}
else
{
- XSelectInput(dpy, window,
- ExposureMask|ButtonPressMask|StructureNotifyMask);
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (dpy, window, &xgwa);
+ XSelectInput (dpy, window,
+ xgwa.your_event_mask | ExposureMask |
+ ButtonPressMask |StructureNotifyMask);
}
}
{
XSync (dpy, False);
+ check_events();
if (holdtime)
sleep(holdtime); /* show complete figure for a bit. */
}
+ check_events();
if (delay)
usleep (delay);
-/* xscreensaver, Copyright (c) 1993, 1995, 1996
+/* xscreensaver, Copyright (c) 1993, 1995, 1996, 1998
* Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
XDrawPoints (dpy, win, gc, points, num_points, CoordModeOrigin);
num_points = 0;
/* if (delay) usleep (delay); */
- /* XSync (dpy, True); */
+ /* XSync (dpy, False); */
}
}
}
total_points = 0;
(void) recurse (0.0, 0.0, 0, dpy, window);
XDrawPoints (dpy, window, gc, points, num_points, CoordModeOrigin);
- XSync (dpy, True);
+ XSync (dpy, False);
if (delay) usleep (delay);
}
{
init_flame (dpy, window);
while (1)
- flame (dpy, window);
+ {
+ flame (dpy, window);
+ screenhack_handle_events (dpy);
+ }
}
* other special, indirect and consequential damages.
*
* Revision History:
+ * 9-Oct-98: dek@cgl.ucsf.edu Added stars.
+ *
* 8-Oct-98: jwz@jwz.org Made the 512x512x1 xearth image be built in.
* Made it possible to load XPM or XBM files.
* Made the planet bounce and roll around.
* 8-Oct-98: Released initial version of "glplanet"
* (David Konerding, dek@cgl.ucsf.edu)
*
- * TODO:
- * 1) stars
- * 3) better earth image
- * 4) "exploding" planet mode-- the surface will expand and explode
- * 5) Fix bug with annoying triangles moving on surface
- *
- *
+ * BUGS:
+ * -bounce is broken
+ *
* For even more spectacular results, grab the images from the "SSysten"
* package (http://www.msu.edu/user/kamelkev/) and do this:
*
"*wireframe: False \n" \
"*light: True \n" \
"*texture: True \n" \
- "*stipple: False \n" \
+ "*stars: True \n" \
"*image: BUILTIN \n" \
"*imageForeground: Green \n" \
"*imageBackground: Blue \n"
#define DEF_ROLL "True"
#define DEF_BOUNCE "True"
#define DEF_TEXTURE "True"
+#define DEF_STARS "True"
#define DEF_LIGHT "True"
-#define DEF_STIPPLE "False"
#define DEF_IMAGE "BUILTIN"
#undef countof
static int do_roll;
static int do_bounce;
static int do_texture;
+static int do_stars;
static int do_light;
-static int do_stipple;
static char *which_image;
static XrmOptionDescRec opts[] = {
{"-rotate", ".glplanet.rotate", XrmoptionNoArg, (caddr_t) "true" },
{"+bounce", ".glplanet.bounce", XrmoptionNoArg, (caddr_t) "false" },
{"-texture", ".glplanet.texture", XrmoptionNoArg, (caddr_t) "true" },
{"+texture", ".glplanet.texture", XrmoptionNoArg, (caddr_t) "false" },
+ {"-stars", ".glplanet.stars", XrmoptionNoArg, (caddr_t) "true" },
+ {"+stars", ".glplanet.stars", XrmoptionNoArg, (caddr_t) "false" },
{"-light", ".glplanet.light", XrmoptionNoArg, (caddr_t) "true" },
{"+light", ".glplanet.light", XrmoptionNoArg, (caddr_t) "false" },
- {"-stipple", ".glplanet.stipple", XrmoptionNoArg, (caddr_t) "true" },
- {"+stipple", ".glplanet.stipple", XrmoptionNoArg, (caddr_t) "false" },
{"-image", ".glplanet.image", XrmoptionSepArg, (caddr_t) 0 },
};
{(caddr_t *) &do_roll, "roll", "Roll", DEF_ROLL, t_Bool},
{(caddr_t *) &do_bounce, "bounce", "Bounce", DEF_BOUNCE, t_Bool},
{(caddr_t *) &do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
+ {(caddr_t *) &do_stars, "stars", "Stars", DEF_STARS, t_Bool},
{(caddr_t *) &do_light, "light", "Light", DEF_LIGHT, t_Bool},
- {(caddr_t *) &do_stipple, "stipple", "Stipple", DEF_STIPPLE, t_Bool},
{(caddr_t *) &which_image, "image", "Image", DEF_IMAGE, t_String},
};
* at the expense of rendering speed
*/
-#define SLICES 25
-#define STACKS 25
-#define NUM_PLATES (STACKS * (SLICES+1))
+#define NUM_STARS 1000
+#define SLICES 15
+#define STACKS 15
/* radius of the sphere- fairly arbitrary */
-#define RADIUS 5.
+#define RADIUS 4
+/* distance away from the sphere model */
+#define DIST 40
-/*-
- * structure for holding the data for an individual plate.
- * RotationRate, Angle, Vector, Translation and Color
- * are not currently used, but may be used in the future
- */
-typedef struct {
- GLfloat RotationRate;
- GLfloat Angle[4];
- GLfloat Vector[3];
- GLfloat Translation[3];
- GLfloat Color[3];
- GLuint platelist;
-} plate;
/* structure for holding the planet data */
typedef struct {
- plate plates[NUM_PLATES];
+ GLuint platelist;
+ GLuint starlist;
+ int screen_width, screen_height;
GLXContext *glx_context;
Window window;
static planetstruct *planets = NULL;
+static inline void
+normalize(GLfloat v[3])
+{
+ GLfloat d = (GLfloat) sqrt((double) (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
+
+ if (d != 0) {
+ v[0] /= d;
+ v[1] /= d;
+ v[2] /= d;
+ } else {
+ v[0] = v[1] = v[2] = 0;
+ }
+}
+
+
/* Set up and enable texturing on our object */
static void
setup_xbm_texture (char *bits, int width, int height,
*out++ = (word & 0x0000FF);
}
- glEnable(GL_TEXTURE_2D);
glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, data);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
{
XImage *image = xpm_to_ximage (dpy, visual, cmap, xpm_data);
- glEnable(GL_TEXTURE_2D);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
image->width, image->height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, image->data);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
return;
}
break;
static void
setup_light(void)
{
-
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_AUTO_NORMAL);
- glEnable(GL_NORMALIZE);
- glShadeModel(GL_SMOOTH);
-
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_LINE_SMOOTH);
+ /* set a number of parameters which make the scene look much nicer */
glEnable(GL_BLEND);
-
- glEnable(GL_LIGHTING);
- glEnable(GL_LIGHT0);
-
- glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
- glEnable(GL_COLOR_MATERIAL);
-
-}
-
-
-/* a stipple pattern */
-static GLubyte halftone[] =
-{
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
-};
-
-/* Set up and enable stippling */
-static void
-setup_stipple(void)
-{
- glEnable(GL_POLYGON_STIPPLE);
- glPolygonStipple(halftone);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glShadeModel(GL_SMOOTH);
}
/* Function for determining points on the surface of the sphere */
-void ParametricSphere(float theta, float rho, float *vector)
+static void inline ParametricSphere(float theta, float rho, GLfloat *vector)
{
- vector[0] = -sin(theta) * sin(rho);
- vector[1] = cos(theta) * sin(rho);
- vector[2] = cos(rho);
+ vector[0] = -sin(theta) * sin(rho);
+ vector[1] = cos(theta) * sin(rho);
+ vector[2] = cos(rho);
+
+#if DO_HELIX
+ vector[0] = -(1- cos(theta)) * cos(rho);
+ vector[1] = -(1- cos(theta)) * sin(rho);
+ vector[2] = -(sin(theta) + rho);
+#endif /* DO_HELIX */
+
return;
}
+/* lame way to generate some random stars */
+void generate_stars(int width, int height)
+{
+ int i;
+/* GLfloat size_range[2], size;*/
+ GLfloat x, y;
+
+ planetstruct *gp = &planets[MI_SCREEN(mi)];
+
+/* glGetFloatv(GL_POINT_SIZE_RANGE, size_range); */
+
+/* printf("size range: %f\t%f\n", size_range[0], size_range[1]); */
+ gp->starlist = glGenLists(1);
+ glNewList(gp->starlist, GL_COMPILE);
+
+ /* this hackery makes the viewport map one-to-one with Vertex arguments */
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluOrtho2D(0, width, 0, height);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ /* disable depth testing for the stars, so they don't obscure the planet */
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_POINT_SMOOTH);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glBegin(GL_POINTS);
+ for(i = 0 ; i < NUM_STARS ; i++)
+ {
+/* size = (drand48()+size_range[0]) * size_range[1]/2.; */
+/* glPointSize(size); */
+ x = drand48()*width;
+ y = drand48()*height;
+ glVertex2f(x,y);
+ }
+ glEnd();
+
+ /* return to original PROJECT and MODELVIEW */
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+
+
+ glEndList();
+
+}
+
/* Initialization function for screen saver */
static void
pinit(ModeInfo * mi)
{
Bool wire = MI_IS_WIREFRAME(mi);
planetstruct *gp = &planets[MI_SCREEN(mi)];
- int i, j, list, dllist;
+ int i, j;
int stacks=STACKS, slices=SLICES;
float radius=RADIUS;
float drho, dtheta;
float rho, theta;
- float vector[3];
- float ds, dt, t, s;;
+ GLfloat vector[3];
+ GLfloat ds, dt, t, s;;
- if (wire)
+ if (wire) {
+ glEnable(GL_LINE_SMOOTH);
do_texture = False;
+ }
/* turn on various options we like */
if (do_texture)
setup_texture(mi);
if (do_light)
setup_light();
- if (do_stipple)
- setup_stipple();
setup_face();
- dllist=glGenLists(NUM_PLATES);
+ if (do_stars) {
+ glEnable(GL_POINT_SMOOTH);
+ generate_stars(MI_WIDTH(mi), MI_HEIGHT(mi));
+ }
- drho = M_PI / stacks;
- dtheta = 2.0 * M_PI / slices;
- ds = 1.0 / slices;
- dt = 1.0 / stacks;
- t = 0.0 ;
-
/*-
- * Generate a huge sphere with quadrilaterals.
- * Each quad is stored in its own display list; this is so we can
- * move the quads around later (not yet done).
+ * Generate a sphere with quadrilaterals.
* Quad vertices are determined using a parametric sphere function.
* For fun, you could generate practically any parameteric surface and
* map an image onto it.
*/
- list = 0;
+ drho = M_PI / stacks;
+ dtheta = 2.0 * M_PI / slices;
+ ds = 1.0 / slices;
+ dt = 1.0 / stacks;
+
+
+ gp->platelist=glGenLists(1);
+ glNewList(gp->platelist, GL_COMPILE);
+
+ glColor3f(1,1,1);
+ glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
+
+ t = 0.0;
for(i=0; i<stacks; i++) {
rho = i * drho;
s = 0.0;
- for(j=0; j<slices+1; j++) {
+ for(j=0; j<slices; j++) {
theta = j * dtheta;
- gp->plates[i].Translation[0] = 0.;
- gp->plates[i].Translation[1] = 0.;
- gp->plates[i].Translation[2] = 0.;
-
- gp->plates[i].RotationRate = 0.;
- gp->plates[i].Angle[0] = 0.;
- gp->plates[i].Angle[1] = 0.;
- gp->plates[i].Angle[2] = 0.;
- gp->plates[i].Angle[3] = 0.;
-
- gp->plates[i].Color[0] = 1.;
- gp->plates[i].Color[1] = 1.;
- gp->plates[i].Color[2] = 1.;
-
- gp->plates[list].platelist = dllist+list;
- glNewList(gp->plates[list].platelist, GL_COMPILE);
- glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
-
- glColor3f(gp->plates[i].Color[0], gp->plates[i].Color[1], gp->plates[i].Color[2]);
glTexCoord2f(s,t);
ParametricSphere(theta, rho, vector);
+ normalize(vector);
glNormal3fv(vector);
+ ParametricSphere(theta, rho, vector);
glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
glTexCoord2f(s,t+dt);
ParametricSphere(theta, rho+drho, vector);
+ normalize(vector);
glNormal3fv(vector);
+ ParametricSphere(theta, rho+drho, vector);
glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
glTexCoord2f(s+ds,t+dt);
ParametricSphere(theta + dtheta, rho+drho, vector);
+ normalize(vector);
glNormal3fv(vector);
+ ParametricSphere(theta + dtheta, rho+drho, vector);
glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
glTexCoord2f(s+ds, t);
ParametricSphere(theta + dtheta, rho, vector);
+ normalize(vector);
glNormal3fv(vector);
+ ParametricSphere(theta + dtheta, rho, vector);
glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
- glEnd();
s = s + ds;
- glEndList();
-
- list++;
}
t = t + dt;
}
+ glEnd();
+ glEndList();
}
static void
-draw(ModeInfo * mi)
+draw_sphere(ModeInfo * mi)
{
- int i;
planetstruct *gp = &planets[MI_SCREEN(mi)];
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+
+ /* turn on the various attributes for making the sphere look nice */
+ if (do_texture)
+ glEnable(GL_TEXTURE_2D);
+
+ if (do_light)
+ {
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
+ glEnable(GL_COLOR_MATERIAL);
+ }
+
+ glCallList(gp->platelist);
- for (i=0; i < NUM_PLATES; i++) {
- glPushMatrix();
- /* currently, the angle and translation are 0, but later this can
- * help us move the surface around */
-#if 0
- glRotatef(gp->plates[i].Angle[0],
- gp->plates[i].Angle[1],
- gp->plates[i].Angle[2],
- gp->plates[i].Angle[3]);
- glTranslatef(gp->plates[i].Translation[0],
- gp->plates[i].Translation[1],
- gp->plates[i].Translation[2]);
-#endif
- glCallList(gp->plates[i].platelist);
- glPopMatrix();
-#if 0
- gp->plates[i].Angle[0] += gp->plates[i].RotationRate;
-#endif
- }
}
gp->box_width = 15.0;
gp->box_height = 15.0;
- gp->box_depth = 60.0;
+ gp->box_depth = 5.0;
gp->tx = 0.0;
gp->ty = 0.0;
/* Standard reshape function */
-#define DIST 40
static void
reshape(int width, int height)
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -DIST);
- /* some messiness for orienting the earth normally */
- glRotatef(90,0,0,1);
- glRotatef(90,0,1,0);
glLightfv(GL_LIGHT0, GL_POSITION, light);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
return;
glDrawBuffer(GL_BACK);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glXMakeCurrent(display, window, *(gp->glx_context));
+
+ if (do_stars) {
+ /* protect our modelview matrix and attributes */
+ glPushMatrix();
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+ {
+ glColor3f(1,1,1);
+ /* draw the star field. */
+ glCallList(gp->starlist);
+
+ }
+ glPopMatrix();
+ glPopAttrib();
+ }
+
+ /* protect our modelview matrix and attributes */
glPushMatrix();
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
{
+ /* this pair of rotations seem to be necessary to orient the earth correctly */
+ glRotatef(90,0,0,1);
+ glRotatef(90,0,1,0);
+
glTranslatef(gp->xpos, gp->ypos, gp->zpos);
glRotatef(gp->tx, 1, 0, 0);
glRotatef(gp->ty, 0, 1, 0);
glRotatef(gp->tz, 0, 0, 1);
- draw(mi);
+ /* draw the sphere */
+ draw_sphere(mi);
}
glPopMatrix();
+ glPopAttrib();
+
+
glFinish();
glXSwapBuffers(display, window);
void
release_planet(ModeInfo * mi)
{
- int i;
if (planets != NULL) {
int screen;
/* Display lists MUST be freed while their glXContext is current. */
glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
- for (i=0; i < NUM_PLATES; i++) {
- if (glIsList(gp->plates[i].platelist))
- glDeleteLists(gp->plates[i].platelist, 1);
- }
+ if (glIsList(gp->platelist))
+ glDeleteLists(gp->platelist, 1);
+ if (glIsList(gp->starlist))
+ glDeleteLists(gp->starlist, 1);
}
}
(void) free((void *) planets);
#endif /* HAVE_GLBINDTEXTURE */
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, interior_color);
- i = countof(points) - 3;
+ i = countof(points) - 9;
do_normal(points[i+0][0], points[i+0][1], 0,
points[i+4][0], points[i+4][1], 0,
points[i+8][0], points[i+8][1], 0);
int bpl, wpl;
XColor colors[255];
+ memset (&xpm_image, 0, sizeof(xpm_image));
+ memset (&xpm_info, 0, sizeof(xpm_info));
result = XpmCreateXpmImageFromData (xpm_data, &xpm_image, &xpm_info);
if (result != XpmSuccess)
{
while (1)
{
run_goop (dpy, window, g);
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
if (delay) usleep (delay);
}
}
-/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
+/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997, 1998
* Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
}
XChangeGC (dpy, gc, GCStipple|GCForeground|GCBackground, &gcv);
XFillRectangle (dpy, window, gc, x, y, w, h);
- XSync (dpy, True);
+ XSync (dpy, False);
}
\f
while (1)
{
greynetic (dpy, window);
+ screenhack_handle_events (dpy);
if (delay) usleep (delay);
}
}
-/* xscreensaver, Copyright (c) 1993, 1995, 1996, 1997
+/* xscreensaver, Copyright (c) 1993, 1995, 1996, 1997, 1998
* Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
: (iterations & 1)))
{
XCopyPlane (dpy, buffer, window, copy_gc, 0, 0, width, height, 0, 0, 1);
- XSync (dpy, True);
+ XSync (dpy, False);
if (anim_p && done)
XFillRectangle (dpy, buffer, erase_gc, 0, 0, width, height);
}
XCopyPlane (dpy, pixmap, window, copy_gc, 0,0,width,height,width,height, 1);
if (buffer)
XCopyPlane (dpy, buffer, window, copy_gc, 0,0,width,height,0,height, 1);
- XSync (dpy, True);
+ XSync (dpy, False);
#endif
if (done)
{
init_circles (dpy, window);
while (1)
- run_circles (dpy, window);
+ {
+ run_circles (dpy, window);
+ screenhack_handle_events (dpy);
+ }
}
else
random_trig(dpy, window, &color, &free_color);
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
sleep ( sleep_time );
+ screenhack_handle_events (dpy);
erase_full_window(dpy, window);
if (free_color) XFreeColors (dpy, cmap, &color.pixel, 1, 0);
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
sleep (1);
}
-/* xscreensaver, Copyright (c) 1992, 1995, 1996
+/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1998
* Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
rotates (y,w);
rotates (z,w);
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
if (delay) usleep (delay);
}
}
xstep = xnextStep;
ystep = ynextStep;
if (!mono_p)
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
}
if (mono_p)
/* in mono-mode, we do all the drawing at the end */
floyd_steinberg (dpy, window);
free (cell);
- XSync (dpy, True);
+ XSync (dpy, False);
}
rotate_colors (dpy, cmap, colors, ncolors,
cycle_direction);
if (cycle_delay) usleep(cycle_delay);
+ screenhack_handle_events (dpy);
}
}
else
- sleep (delay);
+ {
+ screenhack_handle_events (dpy);
+ sleep (delay);
+ }
}
}
}
inter_init(dpy, win, &c);
while(1) {
do_inter(&c);
- if(delay)
- usleep(delay);
+ screenhack_handle_events (dpy);
+ if(delay) usleep(delay);
}
}
while (!done())
{
unshuffle(dpy, window);
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
if (delay) usleep (delay);
}
+ screenhack_handle_events (dpy);
if (delay2)
usleep (delay2 * 1000000);
while (1)
{
draw_objects ();
- XSync (dpy, True);
+ XSync (dpy, False);
if(g.delay) {
- screenhack_usleep(g.delay);
+ screenhack_handle_events (dpy);
+ usleep(g.delay);
}
propogate_objects();
}
#ifdef HAVE_XDBE_EXTENSION
if (usedouble) XdbeSwapBuffers(dpy,&xdswp,1);
#endif /* HAVE_XDBE_EXTENSION */
- XSync(dpy,True);
+ XSync(dpy, False);
+ screenhack_handle_events (dpy);
if (delay) usleep (delay);
}
}
initLMorph();
for (;;) {
animateLMorph();
- screenhack_usleep(delay);
+ screenhack_handle_events (dpy);
+ usleep(delay);
}
}
case Expose:
restart = 1;
break;
+ default:
+ screenhack_handle_event(dpy, &e);
+ break;
}
return(1);
}
}
}
}
- XSync(dpy, 0);
+ XSync(dpy, False);
}
static void
set_maze_sizes (xgwa.width, xgwa.height);
if (! root)
- XSelectInput (dpy, win, ExposureMask|ButtonPressMask|StructureNotifyMask);
+ {
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (dpy, window, &xgwa);
+ XSelectInput (dpy, win,
+ xgwa.your_event_mask | ExposureMask |
+ ButtonPressMask |StructureNotifyMask);
+ }
gc = XCreateGC(dpy, win, 0, 0);
cgc = XCreateGC(dpy, win, 0, 0);
{
init_moire (dpy, window);
moire (dpy, window, offset, colors, ncolors);
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
if (delay)
sleep(delay);
}
-/* xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1997, 1998 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
for (i = 0; i < color_shift; i++)
{
moire2 (dpy, window);
+ screenhack_handle_events (dpy);
if (delay)
usleep(delay);
}
same time (one for each value of x, surprisingly enough)
*/
XSync(dpy, False);
+ screenhack_handle_events (dpy);
if (delay) usleep(delay);
}
}
(randflags & GRAV)
);
+ screenhack_handle_events (dpy);
if (hold) usleep(hold);
if (clear && ++n >= clear) {
while (1)
{
next_fn();
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
usleep (interval * 1000);
}
}
inbetween.blue = from.blue + (to.blue - from.blue) * i / steps ;
XStoreColor (dpy, cmap, &inbetween);
/* If we don't sync, these can bunch up */
- XSync(dpy, 0);
+ XSync(dpy, False);
+ screenhack_handle_events (dpy);
usleep(udelay);
}
}
XColor color;
hsv_to_rgb (random()%360, 1.0, 1.0,
&color.red, &color.green, &color.blue);
- XSync(dpy, 0);
+ XSync(dpy, False);
if (fade_p)
{
foreground.red = color.red;
foreground.blue = color.blue;
foreground.pixel = color.pixel;
}
- XSync(dpy, 0);
+ XSync(dpy, False);
}
/* Fade in by bringing the foreground back from background */
init_pedal (dpy, window);
for (;;) {
pedal (dpy, window);
- XSync(dpy, 0);
+ XSync(dpy, False);
+ screenhack_handle_events (dpy);
if (delay) sleep (delay);
}
}
-/* xscreensaver, Copyright (c) 1992, 1994, 1996
+/* xscreensaver, Copyright (c) 1992, 1994, 1996, 1998
* Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
launch (xlim, ylim, g, dpy, cmap);
}
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
usleep (10000);
for (i = 0; i < how_many; i++)
-/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
+/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997, 1998
* Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
for (qn = q1; *qn; qn++)
{
qix1 (dpy, window, *qn);
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
if (delay) usleep (delay);
}
}
frame++;
XSync(dpy, False);
+ screenhack_handle_events (dpy);
if (delay > 0)
usleep(1000 * delay);
}
-/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
+/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997, 1998
* Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
while (1)
{
rocks_once ();
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
if (delay) usleep (delay);
}
}
-/* xscreensaver, Copyright (c) 1992, 1996 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1992, 1996, 1998 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
j++;
}
XDrawPoints (dpy, window, draw_gc, points, j, CoordModeOrigin);
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
}
sleep ( sleep_time );
XClearWindow (dpy, window);
if (got_color) XFreeColors (dpy, cmap, &color.pixel, 1, 0);
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
sleep (1);
}
#include <X11/CoreP.h>
#include <X11/Shell.h>
#include <X11/StringDefs.h>
+#include <X11/Xutil.h>
#ifdef __sgi
# include <X11/SGIScheme.h> /* for SgiUseSchemes() */
#endif
+static Atom XA_WM_PROTOCOLS, XA_WM_DELETE_WINDOW;
+
+/* Dead-trivial event handling: exits if "q" or "ESC" are typed.
+ Exit if the WM_PROTOCOLS WM_DELETE_WINDOW ClientMessage is received.
+ */
+void
+screenhack_handle_event (Display *dpy, XEvent *event)
+{
+ switch (event->xany.type)
+ {
+ case KeyPress:
+ {
+ KeySym keysym;
+ char c = 0;
+ XLookupString (&event->xkey, &c, 1, &keysym, 0);
+ if (c == 'q' ||
+ c == 'Q' ||
+ c == 3 || /* ^C */
+ c == 27) /* ESC */
+ exit (0);
+ }
+ case ButtonPress:
+ XBell (dpy, 0);
+ break;
+ case ClientMessage:
+ {
+ if (event->xclient.message_type != XA_WM_PROTOCOLS)
+ {
+ char *s = XGetAtomName(dpy, event->xclient.message_type);
+ if (!s) s = "(null)";
+ fprintf (stderr, "%s: unknown ClientMessage %s received!\n",
+ progname, s);
+ }
+ else if (event->xclient.data.l[0] != XA_WM_DELETE_WINDOW)
+ {
+ char *s1 = XGetAtomName(dpy, event->xclient.message_type);
+ char *s2 = XGetAtomName(dpy, event->xclient.data.l[0]);
+ if (!s1) s1 = "(null)";
+ if (!s2) s2 = "(null)";
+ fprintf (stderr, "%s: unknown ClientMessage %s[%s] received!\n",
+ progname, s1, s2);
+ }
+ else
+ {
+ exit (0);
+ }
+ }
+ break;
+ }
+}
+
+
+void
+screenhack_handle_events (Display *dpy)
+{
+ while (XPending (dpy))
+ {
+ XEvent event;
+ XNextEvent (dpy, &event);
+ screenhack_handle_event (dpy, &event);
+ }
+}
+
+
int
main (int argc, char **argv)
XtGetApplicationNameAndClass (dpy, &progname, &progclass);
XSetErrorHandler (screenhack_ehandler);
+ XA_WM_PROTOCOLS = XInternAtom (dpy, "WM_PROTOCOLS", False);
+ XA_WM_DELETE_WINDOW = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
+
{
char *v = (char *) strdup(strchr(screensaver_id, ' '));
- char *s = (char *) strchr(v, ',');
- *s = 0;
- sprintf (version, "%s: from the XScreenSaver%s distribution.",
- progclass, v);
+ char *s1, *s2, *s3, *s4;
+ s1 = (char *) strchr(v, ' '); s1++;
+ s2 = (char *) strchr(s1, ' ');
+ s3 = (char *) strchr(v, '('); s3++;
+ s4 = (char *) strchr(s3, ')');
+ *s2 = 0;
+ *s4 = 0;
+ sprintf (version, "%s: from the XScreenSaver %s distribution (%s.)",
+ progclass, s1, s3);
free(v);
}
}
XtVaSetValues(toplevel, XtNtitle, version, 0);
+
+ /* For screenhack_handle_events(): select KeyPress, and
+ announce that we accept WM_DELETE_WINDOW. */
+ {
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (dpy, window, &xgwa);
+ XSelectInput (dpy, window,
+ xgwa.your_event_mask | KeyPressMask | ButtonPressMask);
+ XChangeProperty (dpy, window, XA_WM_PROTOCOLS, XA_ATOM, 32,
+ PropModeReplace,
+ (unsigned char *) &XA_WM_DELETE_WINDOW, 1);
+ }
}
if (!dont_clear)
extern char *defaults [];
extern void screenhack (Display*,Window);
+extern void screenhack_handle_event (Display*, XEvent*);
+extern void screenhack_handle_events (Display*);
#endif /* __SCREENHACK_H__ */
-/* xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997
+/* xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997, 1998
* Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
XFillRectangle (dpy, d, gc, 0, bitmap_h - yoff, bitmap_w, yoff);
}
- XSync (dpy, True);
+ XSync (dpy, False);
if (delay2) usleep (delay2 * 2);
for (i = 0; i < grid_size; i += pix_inc)
{
points[2].y = points[1].y;
XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
- XSync (dpy, True);
+ XSync (dpy, False);
if (delay) usleep (delay);
}
break;
}
- XSync (dpy, True);
+ XSync (dpy, False);
if (delay) usleep (delay);
}
switch (dir)
while (1)
{
slide1 (dpy, window);
+ screenhack_handle_events (dpy);
if (delay2) usleep (delay2);
}
}
--- /dev/null
+/* sonar.c --- Simulate a sonar screen.
+ *
+ * This is an implementation of a general purpose reporting tool in the
+ * format of a Sonar display. It is designed such that a sensor is read
+ * on every movement of a sweep arm and the results of that sensor are
+ * displayed on the screen. The location of the display points (targets) on the
+ * screen are determined by the current localtion of the sweep and a distance
+ * value associated with the target.
+ *
+ * Currently the only two sensors that are implemented are the simulator
+ * (the default) and the ping sensor. The simulator randomly creates a set
+ * of bogies that move around on the scope while the ping sensor can be
+ * used to display hosts on your network.
+ *
+ * The ping code is only compiled in if you define HAVE_PING, because,
+ * unfortunately, creating an ICMP socket is a privileged operation, the
+ * program needs to be installed SUID root if you want to use the ping
+ * mode. If you check the code you will see that this privilige is given up
+ * immediately after the socket is created.
+ *
+ * It should be easy to extend this code to support other sorts of sensors.
+ * Some ideas:
+ * - search the output of "netstat" for the list of hosts to ping;
+ * - plot the contents of /proc/interrupts;
+ * - plot the process table, by process size, cpu usage, or total time;
+ * - plot the logged on users by idle time or cpu usage.
+ *
+ * Copyright (C) 1998 by Stephen Martin (smartin@canada.com).
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * $Revision: 1.6 $
+ *
+ * Version 1.0 April 27, 1998.
+ * - Initial version
+ * - Submitted to RedHat Screensaver Contest
+ *
+ * Version 1.1 November 3, 1998.
+ * - Added simulation mode.
+ * - Added enhancements by Thomas Bahls <thommy@cs.tu-berlin.de>
+ * - Fixed huge memory leak.
+ * - Submitted to xscreensavers
+ *
+ * Version 1.2
+ * - All ping code is now ifdef-ed by the compile time symbol HAVE_PING;
+ * use -DHAVE_PING to include it when you compile.
+ * - Sweep now uses gradients.
+ * - Fixed portability problems with icmphdr on some systems.
+ * - removed lowColor option/resource.
+ * - changed copyright notice so that it could be included in the xscreensavers
+ * collection.
+ *
+ * Version 1.3 November 16, 1998.
+ * - All ping code is now ifdef-ed by the compile time symbol PING use -DPING
+ * to include it when you compile.
+ * - Sweep now uses gradients.
+ * - Fixed portability problems with icmphdr on some systems.
+ * - removed lowcolour option/resource.
+ * - changed copyright notice so that it could be included in the xscreensavers
+ * collection.
+ *
+ * Version 1.4 November 18, 1998.
+ * - More ping portability fixes.
+ *
+ * Version 1.5 November 19, 1998.
+ * - Synced up with jwz's changes.
+ * - Now need to define HAVE_PING to compile in the ping stuff.
+ */
+
+/* Include Files */
+
+#ifdef HAVE_PING
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/udp.h>
+#include <arpa/inet.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <signal.h>
+#include <limits.h>
+#endif /* HAVE_PING */
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "screenhack.h"
+#include "colors.h"
+#include "hsv.h"
+#include <X11/extensions/XShm.h>
+
+/* Defines */
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a - 50):(b - 10))
+#endif /* MIN */
+
+/* Forward References */
+
+#ifdef HAVE_PING
+static u_short checksum(u_short *, int);
+#endif
+static long delta(struct timeval *, struct timeval *);
+
+/* Data Structures */
+
+/*
+ * The Bogie.
+ *
+ * This represents an object that is visable on the scope.
+ */
+
+typedef struct Bogie {
+ char *name; /* The name of the thing being displayed */
+ int distance; /* The distance to this thing (0 - 100) */
+ int tick; /* The tick that it was found on */
+ int ttl; /* The time to live */
+ int age; /* How long it's been around */
+ struct Bogie *next; /* The next one in the list */
+} Bogie;
+
+/*
+ * Sonar Information.
+ *
+ * This contains all of the runtime information about the sonar scope.
+ */
+
+typedef struct {
+ Display *dpy; /* The X display */
+ Window win; /* The window */
+ GC hi, /* The leading edge of the sweep */
+ lo, /* The trailing part of the sweep */
+ erase, /* Used to erase things */
+ grid, /* Used to draw the grid */
+ text; /* Used to draw text */
+ Colormap cmap; /* The colormap */
+ XFontStruct *font; /* The font to use for the labels */
+ int text_steps; /* How many steps to fade text. */
+ XColor *text_colors; /* Pixel values used to fade text */
+ int sweep_degrees; /* How much of the circle the sweep uses */
+ int sweep_segs; /* How many gradients in the sweep. */
+ XColor *sweep_colors; /* The sweep pixel values */
+ int width, height; /* Window dimensions */
+ int minx, miny, maxx, maxy, /* Bounds of the scope */
+ centrex, centrey, radius; /* Parts of the scope circle */
+ Bogie *visable; /* List of visable objects */
+ int current; /* Current position of sweep */
+
+ int delay; /* how long between each frame of the anim */
+
+} sonar_info;
+
+/*
+ * Variables to support the differnt Sonar modes.
+ */
+
+Bogie *(*sensor)(sonar_info *, void *); /* The current sensor */
+void *sensor_info; /* Information about the sensor */
+
+/*
+ * A list of targets to ping.
+ */
+
+#ifdef HAVE_PING
+typedef struct ping_target {
+ char *name; /* The name of the target */
+ struct sockaddr address; /* The address of the target */
+ struct ping_target *next; /* The next one in the list */
+} ping_target;
+
+/*
+ * Ping Information.
+ *
+ * This contains the information for the ping sensor.
+ */
+
+typedef struct {
+ int icmpsock; /* Socket for sending pings */
+ int pid; /* Our process ID */
+ int seq; /* Packet sequence number */
+ int timeout; /* Timeout value for pings */
+ ping_target *targets; /* List of targets to ping */
+ int numtargets; /* The number of targets to ping */
+} ping_info;
+
+/* Flag to indicate that the timer has expired on us */
+
+static int timer_expired;
+
+
+#endif /* HAVE_PING */
+
+/*
+ * A list of targets for the simulator
+ */
+
+typedef struct sim_target {
+ char *name; /* The name of the target */
+ int nexttick; /* The next tick that this will be seen */
+ int nextdist; /* The distance on that tick */
+ int movedlasttick; /* Flag to indicate we just moved this one */
+} sim_target;
+
+/*
+ * Simulator Information.
+ *
+ * This contains the information for the simulator mode.
+ */
+
+typedef struct {
+ sim_target *teamA; /* The bogies for the A team */
+ int numA; /* The number of bogies in team A */
+ char *teamAID; /* The identifier for bogies in team A */
+ sim_target *teamB; /* The bogies for the B team */
+ int numB; /* The number of bogies in team B */
+ char *teamBID; /* The identifier for bogies in team B */
+} sim_info;
+
+/* Name of the Screensaver hack */
+
+char *progclass="sonar";
+
+/* Application Defaults */
+
+char *defaults [] = {
+ ".background: #000000",
+ ".sweepColor: #00FF00",
+ "*delay: 100000",
+ "*scopeColor: #003300",
+ "*gridColor: #00AA00",
+ "*textColor: #FFFF00",
+ "*ttl: 90",
+ "*mode: default",
+ "*font: fixed",
+ "*sweepDegrees: 30",
+
+ "*textSteps: 80", /* npixels */
+ "*sweepSegments: 80", /* npixels */
+
+#ifdef HAVE_PING
+ "*pingTimeout: 3000",
+ "*pingSource: file",
+ "*pingFile: /etc/hosts",
+ "*pingList: localhost",
+#endif /* HAVE_PING */
+ "*teamAName: F18",
+ "*teamBName: MIG",
+ "*teamACount: 4",
+ "*teamBCount: 4",
+ 0
+};
+
+/* Options passed to this program */
+
+XrmOptionDescRec options [] = {
+ {"-background", ".background", XrmoptionSepArg, 0 },
+ {"-sweep-color", ".sweepColor", XrmoptionSepArg, 0 },
+ {"-scope-color", ".scopeColor", XrmoptionSepArg, 0 },
+ {"-grid-color", ".gridColor", XrmoptionSepArg, 0 },
+ {"-text-color", ".textColor", XrmoptionSepArg, 0 },
+ {"-ttl", ".ttl", XrmoptionSepArg, 0 },
+ {"-mode", ".mode", XrmoptionSepArg, 0 },
+ {"-font", ".font", XrmoptionSepArg, 0 },
+#ifdef HAVE_PING
+ {"-ping-timeout", ".pingTimeout", XrmoptionSepArg, 0 },
+ {"-ping-source", ".pingSource", XrmoptionSepArg, 0 },
+ {"-ping-file", ".pingFile", XrmoptionSepArg, 0 },
+ {"-ping-list", ".pingList", XrmoptionSepArg, 0 },
+#endif /* HAVE_PING */
+ {"-team-a-name", ".teamAName", XrmoptionSepArg, 0 },
+ {"-team-b-name", ".teamBName", XrmoptionSepArg, 0 },
+ {"-team-a-count", ".teamACount", XrmoptionSepArg, 0 },
+ {"-team-b-count", ".teamBCount", XrmoptionSepArg, 0 },
+ { 0, 0, 0, 0 }
+};
+
+/*
+ * The number of ticks that bogies are visable on the screen before they
+ * fade away.
+ */
+
+static int TTL;
+
+/*
+ * Create a new Bogie and set some initial values.
+ *
+ * Args:
+ * name - The name of the bogie.
+ * distance - The distance value.
+ * tick - The tick value.
+ * ttl - The time to live value.
+ *
+ * Returns:
+ * The newly allocated bogie or null if a memory problem occured.
+ */
+
+static Bogie *
+newBogie(char *name, int distance, int tick, int ttl)
+{
+
+ /* Local Variables */
+
+ Bogie *new;
+
+ /* Allocate a bogie and initialize it */
+
+ if ((new = (Bogie *) calloc(1, sizeof(Bogie))) == NULL) {
+ fprintf(stderr, "Out of Memory\n");
+ return NULL;
+ }
+ new->name = name;
+ new->distance = distance;
+ new->tick = tick;
+ new->ttl = ttl;
+ new->age = 0;
+ new->next = (Bogie *) 0;
+ return new;
+}
+
+/*
+ * Free a Bogie.
+ *
+ * Args:
+ * b - The bogie to free.
+ */
+
+static void
+freeBogie(Bogie *b)
+{
+ if (b->name != (char *) 0)
+ free(b->name);
+ free(b);
+}
+
+/*
+ * Find a bogie by name in a list.
+ *
+ * This does a simple linear search of the list for a given name.
+ *
+ * Args:
+ * bl - The Bogie list to search.
+ * name - The name to look for.
+ *
+ * Returns:
+ * The requested Bogie or null if it wasn't found.
+ */
+
+static Bogie *
+findNode(Bogie *bl, char *name)
+{
+
+ /* Local Variables */
+
+ Bogie *p;
+
+ /* Abort if the list is empty or no name is given */
+
+ if ((name == NULL) || (bl == NULL))
+ return NULL;
+
+ /* Search the list for the desired name */
+
+ p = bl;
+ while (p != NULL) {
+ if (strcmp(p->name, name) == 0)
+ return p;
+ p = p->next;
+ }
+
+ /* Not found */
+
+ return NULL;
+}
+
+#ifdef HAVE_PING
+
+/*
+ * Lookup the address for a ping target;
+ *
+ * Args:
+ * target - The ping_target fill in the address for.
+ *
+ * Returns:
+ * 1 if the host was successfully resolved, 0 otherwise.
+ */
+
+static int
+lookupHost(ping_target *target)
+{
+
+ /* Local Variables */
+
+ struct sockaddr_in *iaddr;
+
+ /* Set up the target address we first assume that the name is the
+ IP address as a string */
+
+ iaddr = (struct sockaddr_in *) &(target->address);
+ iaddr->sin_family = AF_INET;
+ if ((iaddr->sin_addr.s_addr = inet_addr(target->name)) == -1) {
+
+ /* Conversion of IP address failed, try to look the host up by name */
+
+ struct hostent *hent = gethostbyname(target->name);
+ if (hent == NULL) {
+ fprintf(stderr, "Could not resolve host %s\n", target->name);
+ return 0;
+ }
+ memcpy(&iaddr->sin_addr, hent->h_addr_list[0],
+ sizeof(iaddr->sin_addr));
+ }
+
+ /* Done */
+
+ return 1;
+}
+
+/*
+ * Create a target for a host.
+ *
+ * Args:
+ * name - The name of the host.
+ *
+ * Returns:
+ * A newly allocated target or null if the host could not be resolved.
+ */
+
+static ping_target *
+newHost(char *name)
+{
+
+ /* Local Variables */
+
+ ping_target *target = NULL;
+
+ /* Create the target */
+
+ if ((target = calloc(1, sizeof(ping_target))) == NULL) {
+ fprintf(stderr, "Out of Memory\n");
+ goto target_init_error;
+ }
+ if ((target->name = strdup(name)) == NULL) {
+ fprintf(stderr, "Out of Memory\n");
+ goto target_init_error;
+ }
+
+ /* Lookup the host */
+
+ if (! lookupHost(target))
+ goto target_init_error;
+
+ /* Done */
+
+ return target;
+
+ /* Handle errors here */
+
+target_init_error:
+ if (target != NULL)
+ free(target);
+ return NULL;
+}
+
+/*
+ * Generate a list of ping targets from the entries in a file.
+ *
+ * Args:
+ * fname - The name of the file. This file is expected to be in the same
+ * format as /etc/hosts.
+ *
+ * Returns:
+ * A list of targets to ping or null if an error occured.
+ */
+
+static ping_target *
+readPingHostsFile(char *fname)
+{
+
+ /* Local Variables */
+
+ FILE *fp;
+ char buf[LINE_MAX];
+ char *p;
+ ping_target *list = NULL;
+ char *addr, *name;
+ ping_target *new;
+
+ /* Make sure we in fact have a file to process */
+
+ if ((fname == NULL) || (fname[0] == '\0')) {
+ fprintf(stderr, "Invalid ping host file name\n");
+ return NULL;
+ }
+
+ /* Open the file */
+
+ if ((fp = fopen(fname, "r")) == NULL) {
+ char msg[1024];
+ sprintf(msg, "Unable to open host file %s", fname);
+ perror(msg);
+ return NULL;
+ }
+
+ /* Read the file line by line */
+
+ while ((p = fgets(buf, LINE_MAX, fp)) != NULL) {
+
+ /*
+ * Parse the line skipping those that start with '#'.
+ * The rest of the lines in the file should be in the same
+ * format as a /etc/hosts file. We are only concerned with
+ * the first two field, the IP address and the name
+ */
+
+ while ((*p == ' ') || (*p == '\t'))
+ p++;
+ if (*p == '#')
+ continue;
+
+ /* Get the name and address */
+
+ name = addr = NULL;
+ if ((addr = strtok(buf, " \t\n")) != NULL)
+ name = strtok(NULL, " \t\n");
+ else
+ continue;
+
+ /* Create a new target using first the name then the address */
+
+ new = NULL;
+ if (name != NULL)
+ new = newHost(name);
+ if (new == NULL)
+ new = newHost(addr);
+
+ /* Add it to the list if we got one */
+
+ if (new != NULL) {
+ new->next = list;
+ list = new;
+ }
+ }
+
+ /* Close the file and return the list */
+
+ fclose(fp);
+ return list;
+}
+
+/*
+ * Generate a list of ping targets from the entries in a string.
+ *
+ * Args:
+ * list - A list of comma separated host names.
+ *
+ * Returns:
+ * A list of targets to ping or null if an error occured.
+ */
+
+static ping_target *
+readPingHostsList(char *list)
+{
+
+ /* Local Variables */
+
+ char *host;
+ ping_target *hostlist = NULL;
+ ping_target *new;
+
+ /* Check that there is a list */
+
+ if ((list == NULL) || (list[0] == '\0'))
+ return NULL;
+
+ /* Loop through the hosts and add them to the list to return */
+
+ host = strtok(list, ",");
+ while (host != NULL) {
+ new = newHost(host);
+ if (new != NULL) {
+ new->next = hostlist;
+ hostlist = new;
+ }
+ host = strtok(NULL, ",");
+ }
+
+ /* Done */
+
+ return hostlist;
+}
+
+/*
+ * Generate a list ping targets consisting of all of the entries on
+ * the same subnet.
+ *
+ * Returns:
+ * A list of all of the hosts on this net.
+ */
+
+static ping_target *
+subnetHostsList(void)
+{
+
+ /* Local Variables */
+
+ char hostname[BUFSIZ];
+ char address[BUFSIZ];
+ struct hostent *hent;
+ char *p;
+ int i;
+ ping_target *new;
+ ping_target *list = NULL;
+
+ /* Get our hostname */
+
+ if (gethostname(hostname, BUFSIZ)) {
+ fprintf(stderr, "Unable to get local hostname\n");
+ return NULL;
+ }
+
+ /* Get our IP address and convert it to a string */
+
+ if ((hent = gethostbyname(hostname)) == NULL) {
+ fprintf(stderr, "Unable to lookup our IP address\n");
+ return NULL;
+ }
+ strcpy(address, inet_ntoa(*((struct in_addr *)hent->h_addr_list[0])));
+
+ /* Get a pointer to the last "." in the string */
+
+ if ((p = strrchr(address, '.')) == NULL) {
+ fprintf(stderr, "Can't parse IP address %s\n", address);
+ return NULL;
+ }
+ p++;
+
+ /* Construct targets for all addresses in this subnet */
+
+ for (i = 254; i > 0; i--) {
+ sprintf(p, "%d", i);
+ new = newHost(address);
+ if (new != NULL) {
+ new->next = list;
+ list = new;
+ }
+ }
+
+ /* Done */
+
+ return list;
+}
+
+/*
+ * Initialize the ping sensor.
+ *
+ * Returns:
+ * A newly allocated ping_info structure or null if an error occured.
+ */
+
+static ping_info *
+init_ping(void)
+{
+
+ /* Local Variables */
+
+ ping_info *pi = NULL; /* The new ping_info struct */
+ char *src; /* The source of the ping hosts */
+ ping_target *pt; /* Used to count the targets */
+
+ /* Create the ping info structure */
+
+ if ((pi = (ping_info *) calloc(1, sizeof(ping_info))) == NULL) {
+ fprintf(stderr, "Out of memory\n");
+ goto ping_init_error;
+ }
+
+ /* Create the ICMP socket and turn off SUID */
+
+ if ((pi->icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
+ perror("Can't create ICMP socket");
+ fprintf(stderr,
+ "%s: this program must be setuid to root for `ping mode' to work.\n",
+ progname);
+ goto ping_init_error;
+ }
+ setuid(getuid());
+ pi->pid = getpid() & 0xFFFF;
+ pi->seq = 0;
+ pi->timeout = get_integer_resource("pingTimeout", "PingTimeout");
+
+ /* Generate a list of targets */
+
+ src = get_string_resource("pingSource", "PingSource");
+ if (strcmp(src, "file") == 0) {
+
+ /*
+ * The list of ping targets is to come from a file in
+ * /etc/hosts format
+ */
+
+ pi->targets = readPingHostsFile(get_string_resource("pingFile",
+ "PingFile"));
+
+ } else if (strcmp(src, "list") == 0) {
+
+ /* The list of hosts is to come from the pinghostlist resource */
+
+ pi->targets = readPingHostsList(get_string_resource("pingList",
+ "PingList"));
+
+ } else if (strcmp(src, "subnet") == 0) {
+
+ pi->targets = subnetHostsList();
+
+ } else {
+
+ /* Unknown source */
+
+ fprintf(stderr, "Illegal pingSource: %s\n", src);
+ goto ping_init_error;
+ }
+
+ /* Make sure there is something to ping */
+
+ if (pi->targets == NULL) {
+ fprintf(stderr, "Nothing to ping");
+ goto ping_init_error;
+ }
+
+ /* Count the targets */
+
+ pt = pi->targets;
+ pi->numtargets = 0;
+ while (pt != NULL) {
+ pi->numtargets++;
+ pt = pt->next;
+ }
+
+ /* Done */
+
+ return pi;
+
+ /* Handle initialization errors here */
+
+ping_init_error:
+ if (pi != NULL)
+ free(pi);
+ return NULL;
+}
+
+/*
+ * Ping a host.
+ *
+ * Args:
+ * pi - The ping information strcuture.
+ * host - The name or IP address of the host to ping (in ascii).
+ */
+
+static void
+sendping(ping_info *pi, ping_target *pt)
+{
+
+ /* Local Variables */
+
+ u_char *packet;
+ struct icmp *icmph;
+ int result;
+
+ /*
+ * Note, we will send the character name of the host that we are
+ * pinging in the packet so that we don't have to keep track of the
+ * name or do an address lookup when it comes back.
+ */
+
+ int pcktsiz = sizeof(struct icmp) + sizeof(struct timeval) +
+ strlen(pt->name) + 1;
+
+ /* Create the ICMP packet */
+
+ if ((packet = (u_char *) malloc(pcktsiz)) == (void *) 0)
+ return; /* Out of memory */
+ icmph = (struct icmp *) packet;
+ icmph->icmp_type = ICMP_ECHO;
+ icmph->icmp_code = 0;
+ icmph->icmp_cksum = 0;
+ icmph->icmp_id = pi->pid;
+ icmph->icmp_seq = pi->seq++;
+ gettimeofday((struct timeval *) &packet[sizeof(struct icmp)],
+ (struct timezone *) 0);
+ strcpy((char *) &packet[sizeof(struct icmp) + sizeof(struct timeval)],
+ pt->name);
+ icmph->icmp_cksum = checksum((u_short *)packet, pcktsiz);
+
+ /* Send it */
+
+ if ((result = sendto(pi->icmpsock, packet, pcktsiz, 0,
+ &pt->address, sizeof(pt->address))) != pcktsiz) {
+#if 0
+ char errbuf[BUFSIZ];
+ sprintf(errbuf, "Error sending ping to %s", pt->name);
+ perror(errbuf);
+#endif
+ }
+}
+
+/*
+ * Catch a signal and do nothing.
+ *
+ * Args:
+ * sig - The signal that was caught.
+ */
+
+static void
+sigcatcher(int sig)
+{
+ timer_expired = 1;
+}
+
+/*
+ * Compute the checksum on a ping packet.
+ *
+ * Args:
+ * packet - A pointer to the packet to compute the checksum for.
+ * size - The size of the packet.
+ *
+ * Returns:
+ * The computed checksum
+ *
+ */
+
+static u_short
+checksum(u_short *packet, int size)
+{
+
+ /* Local Variables */
+
+ register int nleft = size;
+ register u_short *w = packet;
+ register int sum = 0;
+ u_short answer = 0;
+
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator (sum), we add
+ * sequential 16 bit words to it, and at the end, fold back all the
+ * carry bits from the top 16 bits into the lower 16 bits.
+ */
+
+ while (nleft > 1) {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+
+ if (nleft == 1) {
+ *(u_char *)(&answer) = *(u_char *)w ;
+ sum += answer;
+ }
+
+ /* add back carry outs from top 16 bits to low 16 bits */
+
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+
+ /* Done */
+
+ return(answer);
+}
+
+/*
+ * Look for ping replies.
+ *
+ * Retrieve all outstanding ping replies.
+ *
+ * Args:
+ * si - Information about the sonar.
+ * pi - Ping information.
+ * ttl - The time each bogie is to live on the screen
+ *
+ * Returns:
+ * A Bogie list of all the machines that replied.
+ */
+
+static Bogie *
+getping(sonar_info *si, ping_info *pi, int ttl)
+{
+
+ /* Local Variables */
+
+ struct sockaddr from;
+ int fromlen;
+ int result;
+ u_char packet[1024];
+ struct timeval now;
+ struct timeval *then;
+ struct ip *ip;
+ int iphdrlen;
+ struct icmp *icmph;
+ Bogie *bl = NULL;
+ Bogie *new;
+ char *name;
+ struct sigaction sa;
+ struct itimerval it;
+
+ /* Set up a signal to interupt our wait for a packet */
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = sigcatcher;
+ if (sigaction(SIGALRM, &sa, 0) == -1) {
+ perror("Unable to trap sigalarm");
+ exit(1);
+ }
+
+ /* Set up a timer to interupt us if we don't get a packet */
+
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 0;
+ it.it_value.tv_sec = 0;
+ it.it_value.tv_usec = pi->timeout;
+ timer_expired = 0;
+ setitimer(ITIMER_REAL, &it, NULL);
+
+ /* Wait for a result packet */
+
+ fromlen = sizeof(from);
+ while (! timer_expired &&
+ (result = recvfrom(pi->icmpsock, packet, sizeof(packet),
+ 0, &from, &fromlen)) > 0) {
+
+ /* Check the packet */
+
+ gettimeofday(&now, (struct timezone *) 0);
+ ip = (struct ip *) packet;
+ iphdrlen = ip->ip_hl << 2;
+ icmph = (struct icmp *) &packet[iphdrlen];
+
+ /* Was the packet a reply?? */
+
+ if (icmph->icmp_type != ICMP_ECHOREPLY) {
+ /* Ignore anything but ICMP Replies */
+ continue; /* Nope */
+ }
+
+ /* Was it for us? */
+
+ if (icmph->icmp_id != pi->pid) {
+ /* Ignore packets not set from us */
+ continue; /* Nope */
+ }
+
+ /* Copy the name of the bogie */
+
+ if ((name =
+ strdup((char *) &packet[iphdrlen +
+ + sizeof(struct icmp)
+ + sizeof(struct timeval)])) == NULL) {
+ fprintf(stderr, "Out of memory\n");
+ return bl;
+ }
+
+ /* If the name is an IP addr, try to resolve it. */
+ {
+ int iip[4];
+ char c;
+ if (4 == sscanf(name, " %d.%d.%d.%d %c",
+ &iip[0], &iip[1], &iip[2], &iip[3], &c))
+ {
+ unsigned char ip[4];
+ struct hostent *h;
+ ip[0] = iip[0]; ip[1] = iip[1]; ip[2] = iip[2]; ip[3] = iip[3];
+ h = gethostbyaddr ((char *) ip, 4, AF_INET);
+ if (h && h->h_name && *h->h_name)
+ {
+ free (name);
+ name = strdup (h->h_name);
+ }
+ }
+ }
+
+ /* Create the new Bogie and add it to the list we are building */
+
+ if ((new = newBogie(name, 0, si->current, ttl)) == NULL)
+ return bl;
+ new->next = bl;
+ bl = new;
+
+ /* Compute the round trip time */
+
+ then = (struct timeval *) &packet[iphdrlen +
+ sizeof(struct icmp)];
+ new->distance = delta(then, &now) / 100;
+ if (new->distance == 0)
+ new->distance = 2; /* HACK */
+ }
+
+ /* Done */
+
+ return bl;
+}
+
+/*
+ * Ping hosts.
+ *
+ * Args:
+ * si - Sonar Information.
+ * pi - Ping Information.
+ *
+ * Returns:
+ * A list of hosts that replied to pings or null if there were none.
+ */
+
+static Bogie *
+ping(sonar_info *si, void *vpi)
+{
+
+ ping_info *pi = (ping_info *) vpi;
+ static ping_target *ptr = NULL;
+
+ int tick = si->current * -1 + 1;
+ if ((ptr == NULL) && (tick == 1))
+ ptr = pi->targets;
+
+ if (pi->numtargets <= 90) {
+ int xdrant = 90 / pi->numtargets;
+ if ((tick % xdrant) == 0) {
+ if (ptr != (ping_target *) 0) {
+ sendping(pi, ptr);
+ ptr = ptr->next;
+ }
+ }
+
+ } else if (pi->numtargets > 90) {
+ if (ptr != (ping_target *) 0) {
+ sendping(pi, ptr);
+ ptr = ptr->next;
+ }
+ }
+
+ /* Get the results */
+
+ return getping(si, pi, TTL);
+}
+
+#endif /* HAVE_PING */
+
+/*
+ * Calculate the difference between two timevals in microseconds.
+ *
+ * Args:
+ * then - The older timeval.
+ * now - The newer timeval.
+ *
+ * Returns:
+ * The difference between the two in microseconds.
+ */
+
+static long
+delta(struct timeval *then, struct timeval *now)
+{
+ return (((now->tv_sec - then->tv_sec) * 1000000) +
+ (now->tv_usec - then->tv_usec));
+}
+
+/*
+ * Initialize the simulation mode.
+ */
+
+static sim_info *
+init_sim(void)
+{
+
+ /* Local Variables */
+
+ sim_info *si;
+ int i;
+
+ /* Seed the random number generator */
+
+ srand((int) time(NULL));
+
+ /* Create the simulation info structure */
+
+ if ((si = (sim_info *) calloc(1, sizeof(sim_info))) == NULL) {
+ fprintf(stderr, "Out of memory\n");
+ return NULL;
+ }
+
+ /* Team A */
+
+ si->numA = get_integer_resource("teamACount", "TeamACount");
+ if ((si->teamA = (sim_target *)calloc(si->numA, sizeof(sim_target)))
+ == NULL) {
+ free(si);
+ fprintf(stderr, "Out of Memory\n");
+ return NULL;
+ }
+ si->teamAID = get_string_resource("teamAName", "TeamAName");
+ for (i = 0; i < si->numA; i++) {
+ if ((si->teamA[i].name = (char *) malloc(strlen(si->teamAID) + 4))
+ == NULL) {
+ free(si);
+ fprintf(stderr, "Out of Memory\n");
+ return NULL;
+ }
+ sprintf(si->teamA[i].name, "%s%03d", si->teamAID, i+1);
+ si->teamA[i].nexttick = (int) (90.0 * rand() / RAND_MAX);
+ si->teamA[i].nextdist = (int) (100.0 * rand() / RAND_MAX);
+ }
+
+ /* Team B */
+
+ si->numB = get_integer_resource("teamBCount", "TeamBCount");
+ if ((si->teamB = (sim_target *)calloc(si->numB, sizeof(sim_target)))
+ == NULL) {
+ free(si);
+ fprintf(stderr, "Out of Memory\n");
+ return NULL;
+ }
+ si->teamBID = get_string_resource("teamBName", "TeamBName");
+ for (i = 0; i < si->numB; i++) {
+ if ((si->teamB[i].name = (char *) malloc(strlen(si->teamBID) + 4))
+ == NULL) {
+ free(si);
+ fprintf(stderr, "Out of Memory\n");
+ return NULL;
+ }
+ sprintf(si->teamB[i].name, "%s%03d", si->teamBID, i+1);
+ si->teamB[i].nexttick = (int) (90.0 * rand() / RAND_MAX);
+ si->teamB[i].nextdist = (int) (100.0 * rand() / RAND_MAX);
+ }
+
+ /* Done */
+
+ return si;
+}
+
+/*
+ * Initialize the Sonar.
+ *
+ * Args:
+ * dpy - The X display.
+ * win - The X window;
+ *
+ * Returns:
+ * A sonar_info strcuture or null if memory allocation problems occur.
+ */
+
+static sonar_info *
+init_sonar(Display *dpy, Window win)
+{
+
+ /* Local Variables */
+
+ XGCValues gcv;
+ XWindowAttributes xwa;
+ sonar_info *si;
+ XColor start, end;
+ int h1, h2;
+ double s1, s2, v1, v2;
+
+ /* Create the Sonar information structure */
+
+ if ((si = (sonar_info *) calloc(1, sizeof(sonar_info))) == NULL) {
+ fprintf(stderr, "Out of memory\n");
+ return NULL;
+ }
+
+ /* Initialize the structure for the current environment */
+
+ si->dpy = dpy;
+ si->win = win;
+ si->visable = NULL;
+ XGetWindowAttributes(dpy, win, &xwa);
+ si->cmap = xwa.colormap;
+ si->width = xwa.width;
+ si->height = xwa.height;
+ si->centrex = si->width / 2;
+ si->centrey = si->height / 2;
+ si->maxx = si->centrex + MIN(si->centrex, si->centrey) - 10;
+ si->minx = si->centrex - MIN(si->centrex, si->centrey) + 10;
+ si->maxy = si->centrey + MIN(si->centrex, si->centrey) - 10;
+ si->miny = si->centrey - MIN(si->centrex, si->centrey) + 10;
+ si->radius = si->maxx - si->centrex;
+ si->current = 0;
+
+ /* Get the font */
+
+ if (((si->font = XLoadQueryFont(dpy, get_string_resource ("font", "Font")))
+ == NULL) &&
+ ((si->font = XLoadQueryFont(dpy, "fixed")) == NULL)) {
+ fprintf(stderr, "Can't load an appropriate font\n");
+ return NULL;
+ }
+
+ /* Get the delay between animation frames */
+
+ si->delay = get_integer_resource ("delay", "Integer");
+ if (si->delay < 0) si->delay = 0;
+
+ /* Create the Graphics Contexts that will be used to draw things */
+
+ gcv.foreground =
+ get_pixel_resource ("sweepColor", "SweepColor", dpy, si->cmap);
+ si->hi = XCreateGC(dpy, win, GCForeground, &gcv);
+ gcv.font = si->font->fid;
+ si->text = XCreateGC(dpy, win, GCForeground|GCFont, &gcv);
+ gcv.foreground = get_pixel_resource("scopeColor", "ScopeColor",
+ dpy, si->cmap);
+ si->erase = XCreateGC (dpy, win, GCForeground, &gcv);
+ gcv.foreground = get_pixel_resource("gridColor", "GridColor",
+ dpy, si->cmap);
+ si->grid = XCreateGC (dpy, win, GCForeground, &gcv);
+
+ /* Compute pixel values for fading text on the display */
+
+ XParseColor(dpy, si->cmap,
+ get_string_resource("textColor", "TextColor"), &start);
+ XParseColor(dpy, si->cmap,
+ get_string_resource("scopeColor", "ScopeColor"), &end);
+
+ rgb_to_hsv (start.red, start.green, start.blue, &h1, &s1, &v1);
+ rgb_to_hsv (end.red, end.green, end.blue, &h2, &s2, &v2);
+
+ si->text_steps = get_integer_resource("textSteps", "TextSteps");
+ if (si->text_steps < 0 || si->text_steps > 255)
+ si->text_steps = 10;
+
+ si->text_colors = (XColor *) calloc(si->text_steps, sizeof(XColor));
+ make_color_ramp (dpy, si->cmap,
+ h1, s1, v1,
+ h2, s2, v2,
+ si->text_colors, &si->text_steps,
+ False, True, False);
+
+ /* Compute the pixel values for the fading sweep */
+
+ XParseColor(dpy, si->cmap,
+ get_string_resource("sweepColor", "SweepColor"), &start);
+
+ rgb_to_hsv (start.red, start.green, start.blue, &h1, &s1, &v1);
+
+ si->sweep_degrees = get_integer_resource("sweepDegrees", "Degrees");
+ if (si->sweep_degrees <= 0) si->sweep_degrees = 20;
+ if (si->sweep_degrees > 350) si->sweep_degrees = 350;
+
+ si->sweep_segs = get_integer_resource("sweepSegments", "SweepSegments");
+ if (si->sweep_segs < 1 || si->sweep_segs > 255)
+ si->sweep_segs = 255;
+
+ si->sweep_colors = (XColor *) calloc(si->sweep_segs, sizeof(XColor));
+ make_color_ramp (dpy, si->cmap,
+ h1, s1, v1,
+ h2, s2, v2,
+ si->sweep_colors, &si->sweep_segs,
+ False, True, False);
+
+ /* Done */
+
+ return si;
+}
+
+/*
+ * Update the location of a simulated bogie.
+ */
+
+static void
+updateLocation(sim_target *t)
+{
+
+ int xdist, xtick;
+
+ t->movedlasttick = 1;
+ xtick = (int) (3.0 * rand() / RAND_MAX) - 1;
+ xdist = (int) (11.0 * rand() / RAND_MAX) - 5;
+ if (((t->nexttick + xtick) < 90) && ((t->nexttick + xtick) >= 0))
+ t->nexttick += xtick;
+ else
+ t->nexttick -= xtick;
+ if (((t->nextdist + xdist) < 100) && ((t->nextdist+xdist) >= 0))
+ t->nextdist += xdist;
+ else
+ t->nextdist -= xdist;
+}
+
+/*
+ * The simulator. This uses information in the sim_info to simulate a bunch
+ * of bogies flying around on the screen.
+ */
+
+/*
+ * TODO: It would be cool to have the two teams chase each other around and
+ * shoot it out.
+ */
+
+static Bogie *
+simulator(sonar_info *si, void *vinfo)
+{
+
+ /* Local Variables */
+
+ int i;
+ Bogie *list = NULL;
+ Bogie *new;
+ sim_target *t;
+ sim_info *info = (sim_info *) vinfo;
+
+ /* Check team A */
+
+ for (i = 0; i < info->numA; i++) {
+ t = &info->teamA[i];
+ if (!t->movedlasttick && (t->nexttick == (si->current * -1))) {
+ new = newBogie(strdup(t->name), t->nextdist, si->current, TTL);
+ if (list != NULL)
+ new->next = list;
+ list = new;
+ updateLocation(t);
+ } else
+ t->movedlasttick = 0;
+ }
+
+ /* Team B */
+
+ for (i = 0; i < info->numB; i++) {
+ t = &info->teamB[i];
+ if (!t->movedlasttick && (t->nexttick == (si->current * -1))) {
+ new = newBogie(strdup(t->name), t->nextdist, si->current, TTL);
+ if (list != NULL)
+ new->next = list;
+ list = new;
+ t->movedlasttick = 1;
+ updateLocation(t);
+ } else
+ t->movedlasttick = 0;
+ }
+
+ /* Done */
+
+ return list;
+}
+
+/*
+ * Compute the X coordinate of the label.
+ *
+ * Args:
+ * si - The sonar info block.
+ * label - The label that will be drawn.
+ * x - The x coordinate of the bogie.
+ *
+ * Returns:
+ * The x coordinate of the start of the label.
+ */
+
+static int
+computeStringX(sonar_info *si, char *label, int x)
+{
+
+ int width = XTextWidth(si->font, label, strlen(label));
+ return x - (width / 2);
+}
+
+/*
+ * Compute the Y coordinate of the label.
+ *
+ * Args:
+ * si - The sonar information.
+ * y - The y coordinate of the bogie.
+ *
+ * Returns:
+ * The y coordinate of the start of the label.
+ */
+
+/* TODO: Add smarts to keep label in sonar screen */
+
+static int
+computeStringY(sonar_info *si, int y)
+{
+
+ int fheight = si->font->ascent + si->font->descent;
+ return y + 5 + fheight;
+}
+
+/*
+ * Draw a Bogie on the radar screen.
+ *
+ * Args:
+ * si - Sonar Information.
+ * draw - A flag to indicate if the bogie should be drawn or erased.
+ * name - The name of the bogie.
+ * degrees - The number of degrees that it should apprear at.
+ * distance - The distance the object is from the centre.
+ * ttl - The time this bogie has to live.
+ * age - The time this bogie has been around.
+ */
+
+static void
+DrawBogie(sonar_info *si, int draw, char *name, int degrees,
+ int distance, int ttl, int age)
+{
+
+ /* Local Variables */
+
+ int x, y;
+ GC gc;
+ int ox = si->centrex;
+ int oy = si->centrey;
+ int index, delta;
+
+ /* Compute the coordinates of the object */
+
+ distance = (log((double) distance) / 10.0) * si->radius;
+ x = ox + ((double) distance * cos(4.0 * ((double) degrees)/57.29578));
+ y = oy - ((double) distance * sin(4.0 * ((double) degrees)/57.29578));
+
+ /* Set up the graphics context */
+
+ if (draw) {
+
+ /* Here we attempt to compute the distance into the total life of
+ * object that we currently are. This distance is used against
+ * the total lifetime to compute a fraction which is the index of
+ * the color to draw the bogie.
+ */
+
+ if (si->current <= degrees)
+ delta = (si->current - degrees) * -1;
+ else
+ delta = 90 + (degrees - si->current);
+ delta += (age * 90);
+ index = (si->text_steps - 1) * ((float) delta / (90.0 * (float) ttl));
+ gc = si->text;
+ XSetForeground(si->dpy, gc, si->text_colors[index].pixel);
+
+ } else
+ gc = si->erase;
+
+ /* Draw (or erase) the Bogie */
+
+ XFillArc(si->dpy, si->win, gc, x, y, 5, 5, 0, 360 * 64);
+ XDrawString(si->dpy, si->win, gc,
+ computeStringX(si, name, x),
+ computeStringY(si, y), name, strlen(name));
+}
+
+
+/*
+ * Draw the sonar grid.
+ *
+ * Args:
+ * si - Sonar information block.
+ */
+
+static void
+drawGrid(sonar_info *si)
+{
+
+ /* Local Variables */
+
+ int i;
+ int width = si->maxx - si->minx;
+ int height = si->maxy - si->miny;
+
+ /* Draw the circles */
+
+ XDrawArc(si->dpy, si->win, si->grid, si->minx - 10, si->miny - 10,
+ width + 20, height + 20, 0, (360 * 64));
+
+ XDrawArc(si->dpy, si->win, si->grid, si->minx, si->miny,
+ width, height, 0, (360 * 64));
+
+ XDrawArc(si->dpy, si->win, si->grid,
+ (int) (si->minx + (.166 * width)),
+ (int) (si->miny + (.166 * height)),
+ (unsigned int) (.666 * width), (unsigned int)(.666 * height),
+ 0, (360 * 64));
+
+ XDrawArc(si->dpy, si->win, si->grid,
+ (int) (si->minx + (.333 * width)),
+ (int) (si->miny + (.333 * height)),
+ (unsigned int) (.333 * width), (unsigned int) (.333 * height),
+ 0, (360 * 64));
+
+ /* Draw the radial lines */
+
+ for (i = 0; i < 360; i += 10)
+ if (i % 30 == 0)
+ XDrawLine(si->dpy, si->win, si->grid, si->centrex, si->centrey,
+ (int) (si->centrex +
+ (si->radius + 10) * (cos((double) i / 57.29578))),
+ (int) (si->centrey -
+ (si->radius + 10)*(sin((double) i / 57.29578))));
+ else
+ XDrawLine(si->dpy, si->win, si->grid,
+ (int) (si->centrex + si->radius *
+ (cos((double) i / 57.29578))),
+ (int) (si->centrey - si->radius *
+ (sin((double) i / 57.29578))),
+ (int) (si->centrex +
+ (si->radius + 10) * (cos((double) i / 57.29578))),
+ (int) (si->centrey -
+ (si->radius + 10) * (sin((double) i / 57.29578))));
+}
+
+/*
+ * Update the Sonar scope.
+ *
+ * Args:
+ * si - The Sonar information.
+ * bl - A list of bogies to add to the scope.
+ */
+
+static void
+Sonar(sonar_info *si, Bogie *bl)
+{
+
+ /* Local Variables */
+
+ Bogie *bp, *prev;
+ int i;
+
+ /* Check for expired tagets and remove them from the visable list */
+
+ prev = NULL;
+ for (bp = si->visable; bp != NULL; bp = bp->next) {
+
+ /*
+ * Remove it from the visable list if it's expired or we have
+ * a new target with the same name.
+ */
+
+ bp->age ++;
+
+ if (((bp->tick == si->current) && (++bp->age >= bp->ttl)) ||
+ (findNode(bl, bp->name) != NULL)) {
+ DrawBogie(si, 0, bp->name, bp->tick,
+ bp->distance, bp->ttl, bp->age);
+ if (prev == NULL)
+ si->visable = bp->next;
+ else
+ prev->next = bp->next;
+ freeBogie(bp);
+ } else
+ prev = bp;
+ }
+
+ /* Draw the sweep */
+
+ {
+ int seg_deg = (si->sweep_degrees * 64) / si->sweep_segs;
+ int start_deg = si->current * 4 * 64;
+ if (seg_deg <= 0) seg_deg = 1;
+ for (i = 0; i < si->sweep_segs; i++) {
+ XSetForeground(si->dpy, si->hi, si->sweep_colors[i].pixel);
+ XFillArc(si->dpy, si->win, si->hi, si->minx, si->miny,
+ si->maxx - si->minx, si->maxy - si->miny,
+ start_deg + (i * seg_deg),
+ seg_deg);
+ }
+
+ /* Remove the trailing wedge the sonar */
+ XFillArc(si->dpy, si->win, si->erase, si->minx, si->miny,
+ si->maxx - si->minx, si->maxy - si->miny,
+ start_deg + (i * seg_deg),
+ (4 * 64));
+ }
+
+ /* Move the new targets to the visable list */
+
+ for (bp = bl; bp != (Bogie *) 0; bp = bl) {
+ bl = bl->next;
+ bp->next = si->visable;
+ si->visable = bp;
+ }
+
+ /* Draw the visable targets */
+
+ for (bp = si->visable; bp != NULL; bp = bp->next) {
+ if (bp->age < bp->ttl) /* grins */
+ DrawBogie(si, 1, bp->name, bp->tick, bp->distance, bp->ttl,bp->age);
+ }
+
+ /* Redraw the grid */
+
+ drawGrid(si);
+}
+
+/*
+ * Main screen saver hack.
+ *
+ * Args:
+ * dpy - The X display.
+ * win - The X window.
+ */
+
+void
+screenhack(Display *dpy, Window win)
+{
+
+ /* Local Variables */
+
+ sonar_info *si;
+ struct timeval start, finish;
+ Bogie *bl;
+ long sleeptime;
+ char *mode;
+
+ /*
+ * Initialize
+ * Adding new sensors would involve supporting more modes other than
+ * ping and initiailizing the sensor in the same way.
+ */
+
+ mode = get_string_resource("mode", "Mode");
+
+ if (!mode || !*mode || !strcmp(mode, "default")) /* Pick a good default. */
+ {
+#ifdef HAVE_PING
+ if (geteuid() == 0) /* we're root or setuid -- ping will work. */
+ mode = "ping";
+ else
+#endif
+ mode = "simulation";
+ }
+
+#ifdef HAVE_PING
+ if (strcmp(mode, "ping") == 0) {
+ sensor = ping;
+ if ((sensor_info = (void *) init_ping()) == (void *) 0)
+ {
+ fprintf (stderr, "%s: running in `simulation mode' instead.\n",
+ progname);
+ goto SIM;
+ }
+ } else
+#endif /* HAVE_PING */
+ if (strcmp(mode, "simulation") == 0) {
+#ifdef HAVE_PING
+ SIM:
+#endif
+ sensor = simulator;
+ if ((sensor_info = (void *) init_sim()) == NULL)
+ exit(1);
+ } else {
+ fprintf(stderr, "Unsupported Sonar mode: %s\n", mode);
+ fprintf(stderr,
+ "\tCurrently supported modes are `ping' and `simulation'\n");
+ exit(1);
+ }
+ if ((si = init_sonar(dpy, win)) == (sonar_info *) 0)
+ exit(1);
+
+ /* Sonar loop */
+
+ TTL = get_integer_resource("ttl", "TTL");
+
+ while (1) {
+
+ /* Call the sensor and display the results */
+
+ gettimeofday(&start, (struct timezone *) 0);
+ bl = sensor(si, sensor_info);
+ Sonar(si, bl);
+
+ /* Set up and sleep for the next one */
+
+ si->current = (si->current - 1) % 90;
+ XSync (dpy, False);
+ gettimeofday(&finish, (struct timezone *) 0);
+ sleeptime = si->delay - delta(&start, &finish);
+ screenhack_handle_events (dpy);
+ if (sleeptime > 0L)
+ usleep(sleeptime);
+ }
+}
--- /dev/null
+.TH Sonar 1 "3-Nov-98" "X Version 11"
+.SH NAME
+sonar - display a sonar scope
+.SH SYNOPSIS
+.B sonar
+[\-background \fIcolor\fP]
+[\-sweep\-color \fIcolor\fP]
+[\-low\-color \fIcolor\fP]
+[\-scope\-color \fIcolor\fP]
+[\-grid\-color \fIcolor\fP]
+[\-text\-color \fIcolor\fP]
+[\-ttl \fIinteger\fP]
+[\-mode ping]
+[\-font \fIfont\fP]
+[\-ping\-timeout \fIint\fP]
+[\-ping\-source list | file | subnet ]
+[\-ping\-file \fIhosts-file\fP]
+[\-ping\-list \fIhost-name-list\fP]
+[\-team-a-name \fIstring\fP]
+[\-team-b-name \fIstring\fP]
+[\-team-a-count \fIint\fP]
+[\-team-b-count \fIint\fP]
+.SH DESCRIPTION
+The \fIsonar\fP program displays a sonar scope on the computer's screen.
+This scope polls a sensor as the sweep goes around the scope and displays
+what it finds as bogies on the screen. The program is designed to support
+different modes representing different types of sensors. Currently the
+only implemented sensors are a simulator, and a network ping function that
+pings hosts and plots the results on the scope.
+.SH OPTIONS
+.I sonar
+understands the following options:
+.TP 8
+.B \-background \fIColor\fP
+The background Color of the screen not covered by the scope.
+.TP 8
+.B \-sweep\-color \fIColor\fP
+The color of the brightest part of the sweep.
+.TP 8
+.B \-scope\-color \fIColor\fP
+The color of the circular part of the scope.
+.TP 8
+.B \-grid\-color \fIColor\fP
+The color to the grid lines overlaying the scope.
+.TP 8
+.B \-text\-color \fIColor\fP
+The color of the text identifying bogies on the scope.
+.TP 8
+.B \-ttl \fIinteger\fP
+"Time to live": visible time of a Bogie. Try values between 10 (very short)
+and 100.
+.TP 8
+.B \-mode \fIsimulation | ping\fP
+The sensor mode to use, the currently supported modes \fIsimulate\fP (the
+default) and \fIping\fP.
+.TP 8
+.B \-font \fIfont\fP
+The font used to display text on the scope. Default "fixed".
+.TP 8
+.B \-ping\-timeout \fIint\fP
+The amount of time in milliseconds the program will wait for an answer
+to a ping.
+.TP 8
+.B \-ping\-source list | file | subnet
+Th source of the list of hosts to ping. Valid values are: \fIlist\fP,
+\fIfile\fP, \fIsubnet\fP. The first two values are described below;
+and \fIsubnet\fP indicates that the sonar should ping all hosts in the
+same subnet as the current machine. (All addresses are treated
+as class C nets, therefore this will at most ping about 256 hosts.)
+.TP 8
+.B \-ping\-file \fIfilename\fP
+The path to a file in \fI/etc/hosts\fP format. Only used when \fIpingSource\fP
+is set to \fIfile\fP.
+.TP 8
+.B \-ping\-list \fIlist\fP
+A comma separated list of hostnames, eg \fI"pinky,brain,dot"\fP.
+Only used when \fIpingSource\fP is set to \fIlist\fP.
+.TP 8
+.B \-team-a-name \fIstring\fP
+The name of team A, in simulation-mode.
+.TP 8
+.B \-team-b-name \fIstring\fP
+The name of team B, in simulation-mode.
+.TP 8
+.B \-team-a-count \fIint\fP
+The number of bogies on team A, in simulation-mode.
+.TP 8
+.B \-team-b-count \fIint\fP
+The number of bogies on team B, in simulation-mode.
+.SH RESOURCES
+Configuration of the targets to ping is best done by setting X Resources.
+.PP
+.TP 8
+.B background \fI(Color)\fP
+See option \-background, above; default value is \fIblack\fP.
+.TP 8
+.B sweepColor \fI(Color)\fP
+See option \-sweep\-color, above; default value is \fI#00ff00\fP.
+.TP 8
+.B scopeColor \fI(Color)\fP
+See option \-scope\-color, above; default value is \fI#003300\fP.
+.TP 8
+.B gridColor \fI(Color)\fP
+See option \-grid\-color, above; default value is \fI#00aa00\fP.
+.TP 8
+.B textColor \fI(Color)\fP
+See option \-text\-color, above; default value is \fI#ffff00\fP.
+.TP 8
+.B ttl \fI(integer)\fP
+See option \-ttl, above; default value is \fI90\fP or one sweep.
+.TP 8
+.B mode \fI(ping)\fP
+See option \-mode, above. If set to \fIdefault\fP, it will ping hosts if
+possible, otherwise, will run in simulation-mode.
+.TP 8
+.B font \fI(font)\fP
+See option \-font, above; default value is \fIfixed\fP.
+.TP 8
+.B pingTimeout \fI(Integer)\fP
+See option \-pingtimeout, above; default value is \fI3000\fP.
+.TP 8
+.B pingSource \fIlist | file | subnet\fP
+See option \-ping\-source, above. Default value is \fIhostfile\fP.
+.TP 8
+.B pingFile \fIpathname\fP
+See option \-ping\-file, above. Default value is \fI/etc/hosts\fP.
+.TP 8
+.B pingList \fIhost,host,host...\fP
+See option \-ping\-list, above; default value is \fI"localhost"\fP.
+.TP 8
+.B teamAName \fIstring\fP
+See option \-team\-a\-name, above. Default value is "F18".
+.TP 8
+.B teamBName \fIstring\fP
+See option \-teamBName, above. Default value is "MIG".
+.TP 8
+.B teamACount \fIint\fP
+See option \-teamACount, above. Default value is 4.
+.TP 8
+.B teamBCount \fIint\fP
+See option \-teamBCount, above. Default value is 4.
+.SH NOTES
+In order to use the ping sensor, this program must be installed as
+setuid root, so that it can create an ICMP socket.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1),
+.BR ping (8)
+.SH COPYRIGHT
+Copyright \(co 1998 by Stephen Martin. (smartin@canada.com)
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation. No representations are made about the suitability of this
+software for any purpose. It is provided "as is" without express or
+implied warranty.
+
+.SH AUTHORS
+Stephen Martin <smartin@canada.com>, 3-nov-98.
+
+Thanks to Tom Kelly for suggesting a modular approach to the sensor
+amoung other things.
+
+Thomas Bahls <thommy@cs.tu-berlin.de> hacked the "ttl" option, 12-jul-98.
+
-/* xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1997, 1998 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
while (1)
{
run_starfish (dpy, window, s);
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
if (cycle_p && cycle_delay)
{
if (cycle_delay <= delay)
while (i < delay2)
{
rotate_colors (dpy, cmap, colors, ncolors, direction);
+ screenhack_handle_events (dpy);
usleep(cycle_delay);
i += cycle_delay;
}
delay = 0;
}
else
- XSync(disp,True);
+ XSync(disp, False);
+ screenhack_handle_events (disp);
+
/* the delay to try to minimize seizures */
usleep((delay*1000));
count++;
while(scrollcount_x <= scroll)
{
XCopyArea(disp, frame, win, agc,scrollcount_x+offset,scrollcount_y+offset, xgwa.width, xgwa.height, 0,0);
- XSync(disp,True);
+ XSync(disp, False);
scrollcount_x=scrollcount_x+step_size;
scrollcount_y=scrollcount_y+step_size;
usleep(1000*delay);
while(scrollcount_x >= 0)
{
XCopyArea(disp, frame, win, agc,scrollcount_x+offset,scrollcount_y+offset, xgwa.width, xgwa.height, 0,0);
- XSync(disp,True);
+ XSync(disp, False);
scrollcount_y=scrollcount_y+step_size;
scrollcount_x=scrollcount_x-step_size;
usleep(1000*delay);
while(scrollcount_y >= scroll)
{
XCopyArea(disp, frame, win, agc,scrollcount_x+offset,scrollcount_y+offset, xgwa.width, xgwa.height, 0,0);
- XSync(disp,True);
+ XSync(disp, False);
scrollcount_x=scrollcount_x-step_size;
scrollcount_y=scrollcount_y-step_size;
usleep(1000*delay);
while(scrollcount_y > 0)
{
XCopyArea(disp, frame, win, agc,scrollcount_x+offset,scrollcount_y+offset, xgwa.width, xgwa.height, 0,0);
- XSync(disp,True);
+ XSync(disp, False);
scrollcount_y=scrollcount_y-step_size;
scrollcount_x=scrollcount_x+step_size;
usleep(1000*delay);
}
- XSync(disp,True);
+ XSync(disp, False);
scrollcount_x=0;
scrollcount_y=0;
hspace, xgwa.height, False);
y--;
lines--;
- XSync (dpy, True);
+ XSync (dpy, False);
if (delay) usleep (delay * 10);
}
if (y < 0) y = 0;
{
x--;
s--;
- XSync (dpy, True);
+ XSync (dpy, False);
if (delay) usleep (0xFFFF & (delay + (random() % (delay * 10))));
}
}
s = source;
}
- XSync (dpy, True);
+ XSync (dpy, False);
if (delay)
{
usleep (delay);
if (x >= columns) x = 0, y++;
n1++;
}
- XSync (dpy, True);
+ XSync (dpy, False);
usleep (5000000);
while (*n2)
{
n2++;
}
y++;
- XSync (dpy, True);
+ XSync (dpy, False);
usleep (500000);
}
}
+ screenhack_handle_events (dpy);
}
}
do {
hack_draw (&mi);
XSync(dpy, False);
+ screenhack_handle_events (dpy);
if (mi.pause)
usleep(mi.pause);
mi.pause = orig_pause;
break;
case ButtonRelease:
EndRubberBand(canvas, &rubber_data, &event);
+ break;
+ default:
+ screenhack_handle_event (dpy, &event);
break;
}
}
skull (dpy, window, draw_gc, erase_gc, x, y, ww, hh);
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
start_time = time ((time_t *) 0);
if (mono_p)
sleep (delay);
$ sierpinski :== $'mydir'sierpinski
$ slidescreen :== $'mydir'slidescreen
$ slip :== $'mydir'slip
+$ sonar :== $'mydir'sonar
$ sphere :== $'mydir'sphere
$ spiral :== $'mydir'spiral
$ starfish :== $'mydir'starfish
static const char screensaver_id[] =
- "@(#)xscreensaver 3.04 (15-Nov-98), by Jamie Zawinski (jwz@jwz.org)";
+ "@(#)xscreensaver 3.06 (21-Nov-98), by Jamie Zawinski (jwz@jwz.org)";
Begin3
Title: xscreensaver
-Version: 3.04
-Entered-date: 16NOV98
+Version: 3.06
+Entered-date: 22NOV98
Description: A modular screen saver and locker for the X Window System.
Highly customizable: allows the use of any program that
can draw on the root window as a display mode.
Author: jwz@jwz.org (Jamie Zawinski)
Maintained-by: jwz@jwz.org (Jamie Zawinski)
Primary-site: http://www.jwz.org/xscreensaver/
- 964K xscreensaver-3.04.tar.gz
- 25K xscreensaver.README
+ 981K xscreensaver-3.06.tar.gz
+ 26K xscreensaver.README
1K xscreensaver.lsm
Alternate-site: sunsite.unc.edu /pub/Linux/X11/screensavers/
- 964K xscreensaver-3.04.tar.gz
- 25K xscreensaver.README
+ 981K xscreensaver-3.06.tar.gz
+ 26K xscreensaver.README
1K xscreensaver.lsm
Alternate-site: ftp.x.org /contrib/applications/
- 964K xscreensaver-3.04.tar.gz
- 25K xscreensaver.README
+ 981K xscreensaver-3.06.tar.gz
+ 26K xscreensaver.README
1K xscreensaver.lsm
Platforms: Linux, Irix, SunOS, Solaris, HPUX, AIX, FreeBSD, NetBSD,
BSDI, SCO, OSF1, Ultrix, VMS.
Name: xscreensaver
Summary: X screen saver and locker
-Vendor: Jamie Zawinski
-Version: 3.04
+Vendor: Jamie Zawinski <jwz@jwz.org>
+Version: 3.06
Release: 1
URL: http://www.jwz.org/xscreensaver/
Source: xscreensaver-%{version}.tar.gz