From f65151994eba80ecabcdac6eef6fa0dde7e2d45b Mon Sep 17 00:00:00 2001 From: Zygo Blaxell Date: Mon, 2 Mar 2009 00:42:31 -0500 Subject: [PATCH] http://ftp.x.org/contrib/applications/xscreensaver-3.06.tar.gz -rw-r--r-- 1 zblaxell zblaxell 981196 Nov 21 1998 xscreensaver-3.06.tar.gz bfd2d8852b00710dec41f2a2e335c008fe0b84de xscreensaver-3.06.tar.gz --- README | 17 + driver/XScreenSaver.ad.in | 5 +- driver/XScreenSaver_ad.h | 1 + driver/windows.c | 4 +- driver/xscreensaver-command.man | 2 +- driver/xscreensaver-demo.man | 2 +- driver/xscreensaver.h | 8 +- driver/xscreensaver.man | 40 +- hacks/Makefile.in | 24 +- hacks/attraction.c | 5 +- hacks/blitspin.c | 5 +- hacks/bsod.c | 32 +- hacks/bubbles.c | 5 +- hacks/compile_axp.com | 1 + hacks/compile_decc.com | 1 + hacks/coral.c | 8 +- hacks/cynosure.c | 1 + hacks/decayscreen.c | 1 + hacks/deco.c | 7 +- hacks/distort.c | 7 +- hacks/epicycle.c | 13 +- hacks/flame.c | 11 +- hacks/glx/glplanet.c | 347 ++++--- hacks/glx/lament.c | 2 +- hacks/glx/xpm-ximage.c | 2 + hacks/goop.c | 3 +- hacks/greynetic.c | 5 +- hacks/halo.c | 11 +- hacks/helix.c | 7 +- hacks/hypercube.c | 5 +- hacks/imsmap.c | 11 +- hacks/interference.c | 4 +- hacks/jigsaw.c | 4 +- hacks/kaleidescope.c | 5 +- hacks/kumppa.c | 3 +- hacks/lmorph.c | 3 +- hacks/maze.c | 13 +- hacks/moire.c | 3 +- hacks/moire2.c | 3 +- hacks/munch.c | 2 + hacks/noseguy.c | 3 +- hacks/pedal.c | 10 +- hacks/pyro.c | 5 +- hacks/qix.c | 5 +- hacks/rd-bomb.c | 1 + hacks/rocks.c | 5 +- hacks/rorschach.c | 8 +- hacks/screenhack.c | 93 +- hacks/screenhack.h | 2 + hacks/slidescreen.c | 9 +- hacks/sonar.c | 1687 +++++++++++++++++++++++++++++++ hacks/sonar.man | 167 +++ hacks/starfish.c | 6 +- hacks/truchet.c | 14 +- hacks/xjack.c | 11 +- hacks/xlockmore.c | 1 + hacks/xlyap.c | 3 + hacks/xroger-hack.c | 3 +- setup.com | 1 + utils/version.h | 2 +- xscreensaver.lsm | 16 +- xscreensaver.spec | 4 +- 62 files changed, 2402 insertions(+), 287 deletions(-) create mode 100644 hacks/sonar.c create mode 100644 hacks/sonar.man diff --git a/README b/README index e866fcaa..94da385a 100644 --- a/README +++ b/README @@ -77,6 +77,23 @@ http://www.jwz.org/xscreensaver/. ============ +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 diff --git a/driver/XScreenSaver.ad.in b/driver/XScreenSaver.ad.in index 0fee5d3e..ce557228 100644 --- a/driver/XScreenSaver.ad.in +++ b/driver/XScreenSaver.ad.in @@ -4,8 +4,8 @@ ! 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/ @@ -168,6 +168,7 @@ 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\ diff --git a/driver/XScreenSaver_ad.h b/driver/XScreenSaver_ad.h index 61de93c4..b49fc28b 100644 --- a/driver/XScreenSaver_ad.h +++ b/driver/XScreenSaver_ad.h @@ -98,6 +98,7 @@ 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\ diff --git a/driver/windows.c b/driver/windows.c index 73170415..e5231fb0 100644 --- a/driver/windows.c +++ b/driver/windows.c @@ -769,7 +769,7 @@ initialize_screensaver_window_1 (saver_screen_info *ssi) { 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 @@ -789,6 +789,7 @@ initialize_screensaver_window_1 (saver_screen_info *ssi) 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) @@ -1295,6 +1296,7 @@ select_visual (saver_screen_info *ssi, const char *visual_name) 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; diff --git a/driver/xscreensaver-command.man b/driver/xscreensaver-command.man index 5905b85d..48f81a35 100644 --- a/driver/xscreensaver-command.man +++ b/driver/xscreensaver-command.man @@ -11,7 +11,7 @@ .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 diff --git a/driver/xscreensaver-demo.man b/driver/xscreensaver-demo.man index 44611dd7..aee5d9e2 100644 --- a/driver/xscreensaver-demo.man +++ b/driver/xscreensaver-demo.man @@ -11,7 +11,7 @@ .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 diff --git a/driver/xscreensaver.h b/driver/xscreensaver.h index 1926703c..be09025f 100644 --- a/driver/xscreensaver.h +++ b/driver/xscreensaver.h @@ -176,9 +176,11 @@ struct saver_screen_info { 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. */ diff --git a/driver/xscreensaver.man b/driver/xscreensaver.man index 94754b17..ff978401 100644 --- a/driver/xscreensaver.man +++ b/driver/xscreensaver.man @@ -11,7 +11,7 @@ .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 @@ -967,16 +967,30 @@ The .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, @@ -985,8 +999,8 @@ magic "default-n" visual name in the description of the \fBprograms\fP 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 diff --git a/hacks/Makefile.in b/hacks/Makefile.in index de2c10e3..78726220 100644 --- a/hacks/Makefile.in +++ b/hacks/Makefile.in @@ -80,7 +80,8 @@ SRCS = attraction.c blitspin.c bouboule.c braid.c bubbles.c \ 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 \ @@ -94,7 +95,8 @@ OBJS = attraction.o blitspin.o bouboule.o braid.o bubbles.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 \ @@ -104,7 +106,8 @@ EXES = attraction blitspin bouboule braid bubbles decayscreen deco \ 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@ @@ -127,7 +130,8 @@ MEN = attraction.man blitspin.man bouboule.man braid.man \ 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 \ @@ -452,6 +456,9 @@ distort: $(HACK_OBJS) distort.o $(GRAB) $(SHM) 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. # @@ -1422,4 +1429,13 @@ kumppa.o: $(UTILS_SRC)/hsv.h 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 diff --git a/hacks/attraction.c b/hacks/attraction.c index 4b16af97..1a84833b 100644 --- a/hacks/attraction.c +++ b/hacks/attraction.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997 +/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997, 1998 * Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its @@ -605,7 +605,7 @@ run_balls (Display *dpy, Window window) abort (); } - XSync (dpy, True); + XSync (dpy, False); } @@ -661,6 +661,7 @@ screenhack (Display *dpy, Window window) while (1) { run_balls (dpy, window); + screenhack_handle_events (dpy); if (delay) usleep (delay); } } diff --git a/hacks/blitspin.c b/hacks/blitspin.c index cf2941b5..1c527253 100644 --- a/hacks/blitspin.c +++ b/hacks/blitspin.c @@ -299,6 +299,7 @@ init (void) display (self); XSync(dpy, False); + screenhack_handle_events (dpy); } static void @@ -326,7 +327,8 @@ display (Pixmap pixmap) ((xgwa.width-size)>>1)-1, ((xgwa.height-size)>>1)-1, size+2, size+2); */ - XSync (dpy, True); + XSync (dpy, False); + screenhack_handle_events (dpy); } @@ -360,6 +362,7 @@ screenhack (Display *d, Window w) while (1) { rotate (); + screenhack_handle_events (d); if (delay2) usleep (delay2); } } diff --git a/hacks/bsod.c b/hacks/bsod.c index 3f3cd346..4e351605 100644 --- a/hacks/bsod.c +++ b/hacks/bsod.c @@ -157,18 +157,25 @@ double_pixmap(Display *dpy, GC gc, Visual *visual, int depth, Pixmap pixmap, 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--; @@ -1031,7 +1038,12 @@ screenhack (Display *dpy, Window window) 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) { @@ -1053,7 +1065,7 @@ screenhack (Display *dpy, Window window) if (loop > 100) j = -1; if (loop > 200) exit(-1); if (!did) continue; - XSync (dpy, True); + XSync (dpy, False); j = i; loop = 0; } diff --git a/hacks/bubbles.c b/hacks/bubbles.c index 735033d1..913fe037 100644 --- a/hacks/bubbles.c +++ b/hacks/bubbles.c @@ -1,6 +1,6 @@ /* 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 @@ -1302,7 +1302,7 @@ bubbles (Display *dpy, Window window) add_to_mesh(tmp); insert_new_bubble(tmp); - XSync (dpy, True); + XSync (dpy, False); } @@ -1312,6 +1312,7 @@ screenhack (Display *dpy, Window window) init_bubbles (dpy, window); while (1) { bubbles (dpy, window); + screenhack_handle_events (dpy); if (delay) usleep(delay); } diff --git a/hacks/compile_axp.com b/hacks/compile_axp.com index bcfa03f7..fc329272 100644 --- a/hacks/compile_axp.com +++ b/hacks/compile_axp.com @@ -58,6 +58,7 @@ $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS $ 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 diff --git a/hacks/compile_decc.com b/hacks/compile_decc.com index bcfa03f7..fc329272 100644 --- a/hacks/compile_decc.com +++ b/hacks/compile_decc.com @@ -58,6 +58,7 @@ $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS $ 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 diff --git a/hacks/coral.c b/hacks/coral.c index 55186747..7621d5ee 100644 --- a/hacks/coral.c +++ b/hacks/coral.c @@ -170,7 +170,7 @@ coral(Display *dpy, Window window) XDrawPoints(dpy, window, draw_gc, pointbuf, npoints, CoordModeOrigin); npoints = 0; - XSync(dpy, True); + XSync(dpy, False); } if (color) { @@ -181,7 +181,7 @@ coral(Display *dpy, Window window) } if( 0 == nwalkers ) { - XSync(dpy, True); + XSync(dpy, False); free(pointbuf); return; } @@ -217,8 +217,9 @@ coral(Display *dpy, Window window) XDrawPoints(dpy, window, draw_gc, pointbuf, npoints, CoordModeOrigin); npoints = 0; - XSync(dpy, True); + XSync(dpy, False); } + screenhack_handle_events (dpy); usleep(delay2); } } @@ -253,6 +254,7 @@ Window window; while( 1 ) { init_coral(dpy, window); coral(dpy, window); + screenhack_handle_events (dpy); if( delay ) sleep(delay); erase_full_window(dpy, window); } diff --git a/hacks/cynosure.c b/hacks/cynosure.c index 56882580..052a9444 100644 --- a/hacks/cynosure.c +++ b/hacks/cynosure.c @@ -214,6 +214,7 @@ void screenhack(Display *d, Window w) } paint(); XSync(dpy, False); + screenhack_handle_events (dpy); if (delay) usleep(delay); } diff --git a/hacks/decayscreen.c b/hacks/decayscreen.c index 7b91f63b..da6a5fef 100644 --- a/hacks/decayscreen.c +++ b/hacks/decayscreen.c @@ -207,6 +207,7 @@ screenhack (Display *dpy, Window window) for (i = 0; i < 100; i++) decay1 (dpy, window); XSync(dpy, False); + screenhack_handle_events (dpy); if (delay) usleep (delay); } } diff --git a/hacks/deco.c b/hacks/deco.c index 3b49c09a..ae908051 100644 --- a/hacks/deco.c +++ b/hacks/deco.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1997 Jamie Zawinski +/* xscreensaver, Copyright (c) 1997, 1998 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -133,7 +133,8 @@ screenhack (Display *dpy, Window window) 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) @@ -144,6 +145,8 @@ screenhack (Display *dpy, Window window) 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); } diff --git a/hacks/distort.c b/hacks/distort.c index 7eed6281..dc8852d0 100644 --- a/hacks/distort.c +++ b/hacks/distort.c @@ -432,8 +432,8 @@ void reflect_draw(int k) 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, @@ -592,7 +592,8 @@ void screenhack(Display *dpy, Window window) draw(k); } - XSync(dpy, True); + XSync(dpy, False); + screenhack_handle_events (dpy); if (delay) usleep(delay); } diff --git a/hacks/epicycle.c b/hacks/epicycle.c index eed186ca..b812e6ae 100644 --- a/hacks/epicycle.c +++ b/hacks/epicycle.c @@ -534,6 +534,10 @@ check_events (void) /* X event handler [ rhess ] */ 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 @@ -580,8 +584,11 @@ setup(void) } else { - XSelectInput(dpy, window, - ExposureMask|ButtonPressMask|StructureNotifyMask); + XWindowAttributes xgwa; + XGetWindowAttributes (dpy, window, &xgwa); + XSelectInput (dpy, window, + xgwa.your_event_mask | ExposureMask | + ButtonPressMask |StructureNotifyMask); } } @@ -814,6 +821,7 @@ screenhack(Display *disp, Window win) { XSync (dpy, False); + check_events(); if (holdtime) sleep(holdtime); /* show complete figure for a bit. */ @@ -821,6 +829,7 @@ screenhack(Display *disp, Window win) } + check_events(); if (delay) usleep (delay); diff --git a/hacks/flame.c b/hacks/flame.c index 521d3cb7..0cc7f659 100644 --- a/hacks/flame.c +++ b/hacks/flame.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1993, 1995, 1996 +/* xscreensaver, Copyright (c) 1993, 1995, 1996, 1998 * Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its @@ -167,7 +167,7 @@ recurse (double x, double y, int l, Display *dpy, Window win) XDrawPoints (dpy, win, gc, points, num_points, CoordModeOrigin); num_points = 0; /* if (delay) usleep (delay); */ - /* XSync (dpy, True); */ + /* XSync (dpy, False); */ } } } @@ -356,7 +356,7 @@ flame (Display *dpy, Window window) 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); } @@ -405,5 +405,8 @@ screenhack (Display *dpy, Window window) { init_flame (dpy, window); while (1) - flame (dpy, window); + { + flame (dpy, window); + screenhack_handle_events (dpy); + } } diff --git a/hacks/glx/glplanet.c b/hacks/glx/glplanet.c index ea74f429..7c71fc7d 100644 --- a/hacks/glx/glplanet.c +++ b/hacks/glx/glplanet.c @@ -20,6 +20,8 @@ static const char sccsid[] = "@(#)plate.c 4.07 97/11/24 xlockmore"; * 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. @@ -27,13 +29,9 @@ static const char sccsid[] = "@(#)plate.c 4.07 97/11/24 xlockmore"; * 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: * @@ -68,7 +66,7 @@ static const char sccsid[] = "@(#)plate.c 4.07 97/11/24 xlockmore"; "*wireframe: False \n" \ "*light: True \n" \ "*texture: True \n" \ - "*stipple: False \n" \ + "*stars: True \n" \ "*image: BUILTIN \n" \ "*imageForeground: Green \n" \ "*imageBackground: Blue \n" @@ -102,8 +100,8 @@ static const char sccsid[] = "@(#)plate.c 4.07 97/11/24 xlockmore"; #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 @@ -113,8 +111,8 @@ static int do_rotate; 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" }, @@ -125,10 +123,10 @@ static XrmOptionDescRec opts[] = { {"+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 }, }; @@ -137,8 +135,8 @@ static argtype vars[] = { {(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}, }; @@ -162,32 +160,23 @@ ModStruct planet_description = * 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; @@ -205,6 +194,21 @@ typedef struct { 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, @@ -233,7 +237,6 @@ 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); @@ -242,8 +245,8 @@ setup_xbm_texture (char *bits, int width, int height, 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); } @@ -263,7 +266,6 @@ setup_file_texture (ModeInfo *mi, char *filename) { 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); @@ -275,8 +277,8 @@ setup_file_texture (ModeInfo *mi, char *filename) 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; @@ -354,52 +356,10 @@ setup_texture(ModeInfo * mi) 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); } @@ -413,148 +373,194 @@ setup_face(void) /* 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; iplates[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 - } } @@ -567,7 +573,7 @@ pick_velocity (ModeInfo * mi) 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; @@ -633,7 +639,6 @@ rotate_and_move (ModeInfo * mi) /* Standard reshape function */ -#define DIST 40 static void reshape(int width, int height) { @@ -652,9 +657,6 @@ 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); @@ -727,18 +729,44 @@ draw_planet(ModeInfo * mi) 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); @@ -749,7 +777,6 @@ draw_planet(ModeInfo * mi) void release_planet(ModeInfo * mi) { - int i; if (planets != NULL) { int screen; @@ -760,10 +787,10 @@ release_planet(ModeInfo * mi) /* 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); diff --git a/hacks/glx/lament.c b/hacks/glx/lament.c index 8a236095..d79376dd 100644 --- a/hacks/glx/lament.c +++ b/hacks/glx/lament.c @@ -565,7 +565,7 @@ star(ModeInfo *mi, Bool top, Bool wire) #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); diff --git a/hacks/glx/xpm-ximage.c b/hacks/glx/xpm-ximage.c index 6ac712f0..44f64dbf 100644 --- a/hacks/glx/xpm-ximage.c +++ b/hacks/glx/xpm-ximage.c @@ -63,6 +63,8 @@ xpm_to_ximage (Display *dpy, Visual *visual, Colormap cmap, char **xpm_data) 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) { diff --git a/hacks/goop.c b/hacks/goop.c index 233708e6..ef0e8e66 100644 --- a/hacks/goop.c +++ b/hacks/goop.c @@ -528,7 +528,8 @@ screenhack (Display *dpy, Window window) while (1) { run_goop (dpy, window, g); - XSync (dpy, True); + XSync (dpy, False); + screenhack_handle_events (dpy); if (delay) usleep (delay); } } diff --git a/hacks/greynetic.c b/hacks/greynetic.c index b2ddec4c..1377c95d 100644 --- a/hacks/greynetic.c +++ b/hacks/greynetic.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997 +/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997, 1998 * Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its @@ -152,7 +152,7 @@ greynetic (Display *dpy, Window window) } XChangeGC (dpy, gc, GCStipple|GCForeground|GCBackground, &gcv); XFillRectangle (dpy, window, gc, x, y, w, h); - XSync (dpy, True); + XSync (dpy, False); } @@ -177,6 +177,7 @@ screenhack (Display *dpy, Window window) while (1) { greynetic (dpy, window); + screenhack_handle_events (dpy); if (delay) usleep (delay); } } diff --git a/hacks/halo.c b/hacks/halo.c index 474f0bc6..7e8da8a2 100644 --- a/hacks/halo.c +++ b/hacks/halo.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1993, 1995, 1996, 1997 +/* xscreensaver, Copyright (c) 1993, 1995, 1996, 1997, 1998 * Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its @@ -365,7 +365,7 @@ run_circles (Display *dpy, Window window) : (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); } @@ -374,7 +374,7 @@ run_circles (Display *dpy, Window window) 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) @@ -446,5 +446,8 @@ screenhack (Display *dpy, Window window) { init_circles (dpy, window); while (1) - run_circles (dpy, window); + { + run_circles (dpy, window); + screenhack_handle_events (dpy); + } } diff --git a/hacks/helix.c b/hacks/helix.c index c2d81fa2..27c9d437 100644 --- a/hacks/helix.c +++ b/hacks/helix.c @@ -268,13 +268,16 @@ random_helix_or_trig (Display *dpy, Window window) 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); } diff --git a/hacks/hypercube.c b/hacks/hypercube.c index 560f1306..5150ec3b 100644 --- a/hacks/hypercube.c +++ b/hacks/hypercube.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1992, 1995, 1996 +/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1998 * Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its @@ -210,7 +210,8 @@ hyper (double xy, double xz, double yz, double xw, double yw, double zw) rotates (y,w); rotates (z,w); - XSync (dpy, True); + XSync (dpy, False); + screenhack_handle_events (dpy); if (delay) usleep (delay); } } diff --git a/hacks/imsmap.c b/hacks/imsmap.c index fa861ac0..15cb66ae 100644 --- a/hacks/imsmap.c +++ b/hacks/imsmap.c @@ -439,14 +439,15 @@ draw_map (Display *dpy, Window window) 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); } @@ -493,10 +494,14 @@ screenhack (Display *dpy, Window window) 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); + } } } } diff --git a/hacks/interference.c b/hacks/interference.c index d877a01b..d856f30e 100644 --- a/hacks/interference.c +++ b/hacks/interference.c @@ -450,7 +450,7 @@ void screenhack(Display *dpy, Window win) inter_init(dpy, win, &c); while(1) { do_inter(&c); - if(delay) - usleep(delay); + screenhack_handle_events (dpy); + if(delay) usleep(delay); } } diff --git a/hacks/jigsaw.c b/hacks/jigsaw.c index 83dcbe92..246c9da7 100644 --- a/hacks/jigsaw.c +++ b/hacks/jigsaw.c @@ -567,10 +567,12 @@ screenhack (Display *dpy, Window window) 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); diff --git a/hacks/kaleidescope.c b/hacks/kaleidescope.c index 78890147..6e66fdd8 100644 --- a/hacks/kaleidescope.c +++ b/hacks/kaleidescope.c @@ -444,9 +444,10 @@ screenhack (Display *dpy, Window window) 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(); } diff --git a/hacks/kumppa.c b/hacks/kumppa.c index 640a856e..bcc137af 100644 --- a/hacks/kumppa.c +++ b/hacks/kumppa.c @@ -529,7 +529,8 @@ while (0==0) #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); } } diff --git a/hacks/lmorph.c b/hacks/lmorph.c index f372c1ee..11099d26 100644 --- a/hacks/lmorph.c +++ b/hacks/lmorph.c @@ -507,6 +507,7 @@ screenhack(Display *disp, Window win) initLMorph(); for (;;) { animateLMorph(); - screenhack_usleep(delay); + screenhack_handle_events (dpy); + usleep(delay); } } diff --git a/hacks/maze.c b/hacks/maze.c index 7690555d..40edf41b 100644 --- a/hacks/maze.c +++ b/hacks/maze.c @@ -201,6 +201,9 @@ check_events (void) /* X event handler [ rhess ] */ case Expose: restart = 1; break; + default: + screenhack_handle_event(dpy, &e); + break; } return(1); } @@ -1367,7 +1370,7 @@ find_dead_regions(void) } } } - XSync(dpy, 0); + XSync(dpy, False); } static void @@ -1612,7 +1615,13 @@ screenhack(Display *display, Window window) 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); diff --git a/hacks/moire.c b/hacks/moire.c index f01fa28f..9b95c6b9 100644 --- a/hacks/moire.c +++ b/hacks/moire.c @@ -230,7 +230,8 @@ screenhack (Display *dpy, Window window) { init_moire (dpy, window); moire (dpy, window, offset, colors, ncolors); - XSync (dpy, True); + XSync (dpy, False); + screenhack_handle_events (dpy); if (delay) sleep(delay); } diff --git a/hacks/moire2.c b/hacks/moire2.c index e714b5e0..96bfd9ac 100644 --- a/hacks/moire2.c +++ b/hacks/moire2.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1997 Jamie Zawinski +/* xscreensaver, Copyright (c) 1997, 1998 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -270,6 +270,7 @@ screenhack (Display *dpy, Window window) for (i = 0; i < color_shift; i++) { moire2 (dpy, window); + screenhack_handle_events (dpy); if (delay) usleep(delay); } diff --git a/hacks/munch.c b/hacks/munch.c index 84ff9608..b3cd7351 100644 --- a/hacks/munch.c +++ b/hacks/munch.c @@ -133,6 +133,7 @@ static void munchOnce (Display* dpy, Window w, same time (one for each value of x, surprisingly enough) */ XSync(dpy, False); + screenhack_handle_events (dpy); if (delay) usleep(delay); } } @@ -246,6 +247,7 @@ screenhack (dpy, w) Display *dpy; Window w; (randflags & GRAV) ); + screenhack_handle_events (dpy); if (hold) usleep(hold); if (clear && ++n >= clear) { diff --git a/hacks/noseguy.c b/hacks/noseguy.c index 0afb52c8..9ea9f4e5 100644 --- a/hacks/noseguy.c +++ b/hacks/noseguy.c @@ -713,7 +713,8 @@ screenhack (Display *d, Window w) while (1) { next_fn(); - XSync (dpy, True); + XSync (dpy, False); + screenhack_handle_events (dpy); usleep (interval * 1000); } } diff --git a/hacks/pedal.c b/hacks/pedal.c index 4306f8a2..7f8e5bd6 100644 --- a/hacks/pedal.c +++ b/hacks/pedal.c @@ -276,7 +276,8 @@ fade_foreground (Display *dpy, Colormap cmap, 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); } } @@ -317,7 +318,7 @@ pedal (Display *dpy, Window window) 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; @@ -335,7 +336,7 @@ pedal (Display *dpy, Window window) foreground.blue = color.blue; foreground.pixel = color.pixel; } - XSync(dpy, 0); + XSync(dpy, False); } /* Fade in by bringing the foreground back from background */ @@ -374,7 +375,8 @@ screenhack (Display *dpy, Window window) init_pedal (dpy, window); for (;;) { pedal (dpy, window); - XSync(dpy, 0); + XSync(dpy, False); + screenhack_handle_events (dpy); if (delay) sleep (delay); } } diff --git a/hacks/pyro.c b/hacks/pyro.c index 05c12763..ddace391 100644 --- a/hacks/pyro.c +++ b/hacks/pyro.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1992, 1994, 1996 +/* xscreensaver, Copyright (c) 1992, 1994, 1996, 1998 * Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its @@ -164,7 +164,8 @@ pyro (Display *dpy, Window window, Colormap cmap) 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++) diff --git a/hacks/qix.c b/hacks/qix.c index c19f3bc6..924b5422 100644 --- a/hacks/qix.c +++ b/hacks/qix.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997 +/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997, 1998 * Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its @@ -504,7 +504,8 @@ screenhack (Display *dpy, Window window) for (qn = q1; *qn; qn++) { qix1 (dpy, window, *qn); - XSync (dpy, True); + XSync (dpy, False); + screenhack_handle_events (dpy); if (delay) usleep (delay); } } diff --git a/hacks/rd-bomb.c b/hacks/rd-bomb.c index 990abcf8..a537eadc 100644 --- a/hacks/rd-bomb.c +++ b/hacks/rd-bomb.c @@ -541,6 +541,7 @@ screenhack (Display *dpy, Window win) frame++; XSync(dpy, False); + screenhack_handle_events (dpy); if (delay > 0) usleep(1000 * delay); } diff --git a/hacks/rocks.c b/hacks/rocks.c index aceef3bc..e5e0df5b 100644 --- a/hacks/rocks.c +++ b/hacks/rocks.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997 +/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997, 1998 * Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its @@ -527,7 +527,8 @@ screenhack (Display *dpy, Window window) while (1) { rocks_once (); - XSync (dpy, True); + XSync (dpy, False); + screenhack_handle_events (dpy); if (delay) usleep (delay); } } diff --git a/hacks/rorschach.c b/hacks/rorschach.c index 3c1a20e5..430fa9df 100644 --- a/hacks/rorschach.c +++ b/hacks/rorschach.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1992, 1996 Jamie Zawinski +/* xscreensaver, Copyright (c) 1992, 1996, 1998 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -92,7 +92,8 @@ hurm (Display *dpy, Window window) j++; } XDrawPoints (dpy, window, draw_gc, points, j, CoordModeOrigin); - XSync (dpy, True); + XSync (dpy, False); + screenhack_handle_events (dpy); } sleep ( sleep_time ); @@ -100,7 +101,8 @@ hurm (Display *dpy, Window window) 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); } diff --git a/hacks/screenhack.c b/hacks/screenhack.c index 4d169939..0e1c678e 100644 --- a/hacks/screenhack.c +++ b/hacks/screenhack.c @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef __sgi # include /* for SgiUseSchemes() */ @@ -167,6 +168,70 @@ extern void pre_merge_options (void); #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) @@ -208,12 +273,20 @@ 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); } @@ -359,6 +432,18 @@ main (int argc, char **argv) } 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) diff --git a/hacks/screenhack.h b/hacks/screenhack.h index bb0344fb..63222520 100644 --- a/hacks/screenhack.h +++ b/hacks/screenhack.h @@ -94,5 +94,7 @@ extern XrmOptionDescRec options []; extern char *defaults []; extern void screenhack (Display*,Window); +extern void screenhack_handle_event (Display*, XEvent*); +extern void screenhack_handle_events (Display*); #endif /* __SCREENHACK_H__ */ diff --git a/hacks/slidescreen.c b/hacks/slidescreen.c index 9415ac22..c2fc0332 100644 --- a/hacks/slidescreen.c +++ b/hacks/slidescreen.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997 +/* xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997, 1998 * Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its @@ -197,7 +197,7 @@ init_slide (Display *dpy, Window window) 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) { @@ -228,7 +228,7 @@ init_slide (Display *dpy, Window window) points[2].y = points[1].y; XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin); - XSync (dpy, True); + XSync (dpy, False); if (delay) usleep (delay); } @@ -309,7 +309,7 @@ slide1 (Display *dpy, Window window) break; } - XSync (dpy, True); + XSync (dpy, False); if (delay) usleep (delay); } switch (dir) @@ -357,6 +357,7 @@ screenhack (Display *dpy, Window window) while (1) { slide1 (dpy, window); + screenhack_handle_events (dpy); if (delay2) usleep (delay2); } } diff --git a/hacks/sonar.c b/hacks/sonar.c new file mode 100644 index 00000000..3c492189 --- /dev/null +++ b/hacks/sonar.c @@ -0,0 +1,1687 @@ +/* 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 + * - 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* HAVE_PING */ +#include +#include +#include +#include "screenhack.h" +#include "colors.h" +#include "hsv.h" +#include + +/* 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); + } +} diff --git a/hacks/sonar.man b/hacks/sonar.man new file mode 100644 index 00000000..7fe77612 --- /dev/null +++ b/hacks/sonar.man @@ -0,0 +1,167 @@ +.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 , 3-nov-98. + +Thanks to Tom Kelly for suggesting a modular approach to the sensor +amoung other things. + +Thomas Bahls hacked the "ttl" option, 12-jul-98. + diff --git a/hacks/starfish.c b/hacks/starfish.c index e368164d..070c0341 100644 --- a/hacks/starfish.c +++ b/hacks/starfish.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1997 Jamie Zawinski +/* xscreensaver, Copyright (c) 1997, 1998 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -470,8 +470,9 @@ screenhack (Display *dpy, Window window) 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) @@ -518,6 +519,7 @@ screenhack (Display *dpy, Window window) while (i < delay2) { rotate_colors (dpy, cmap, colors, ncolors, direction); + screenhack_handle_events (dpy); usleep(cycle_delay); i += cycle_delay; } diff --git a/hacks/truchet.c b/hacks/truchet.c index 66cec3db..cb539134 100644 --- a/hacks/truchet.c +++ b/hacks/truchet.c @@ -458,8 +458,10 @@ void screenhack(Display *disp, Window win) delay = 0; } else - XSync(disp,True); + XSync(disp, False); + screenhack_handle_events (disp); + /* the delay to try to minimize seizures */ usleep((delay*1000)); count++; @@ -488,7 +490,7 @@ static void scroll_area(Display *disp, Window win, int delay, int step_size) 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); @@ -496,7 +498,7 @@ static void scroll_area(Display *disp, Window win, int delay, int step_size) 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); @@ -504,7 +506,7 @@ static void scroll_area(Display *disp, Window win, int delay, int step_size) 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); @@ -512,13 +514,13 @@ static void scroll_area(Display *disp, Window win, int delay, int step_size) 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; diff --git a/hacks/xjack.c b/hacks/xjack.c index 8f8c1a34..4f50635b 100644 --- a/hacks/xjack.c +++ b/hacks/xjack.c @@ -171,7 +171,7 @@ screenhack (Display *dpy, Window window) hspace, xgwa.height, False); y--; lines--; - XSync (dpy, True); + XSync (dpy, False); if (delay) usleep (delay * 10); } if (y < 0) y = 0; @@ -238,7 +238,7 @@ screenhack (Display *dpy, Window window) { x--; s--; - XSync (dpy, True); + XSync (dpy, False); if (delay) usleep (0xFFFF & (delay + (random() % (delay * 10)))); } } @@ -306,7 +306,7 @@ screenhack (Display *dpy, Window window) s = source; } - XSync (dpy, True); + XSync (dpy, False); if (delay) { usleep (delay); @@ -340,7 +340,7 @@ screenhack (Display *dpy, Window window) if (x >= columns) x = 0, y++; n1++; } - XSync (dpy, True); + XSync (dpy, False); usleep (5000000); while (*n2) { @@ -353,9 +353,10 @@ screenhack (Display *dpy, Window window) n2++; } y++; - XSync (dpy, True); + XSync (dpy, False); usleep (500000); } } + screenhack_handle_events (dpy); } } diff --git a/hacks/xlockmore.c b/hacks/xlockmore.c index ff18c4a0..62c2dc79 100644 --- a/hacks/xlockmore.c +++ b/hacks/xlockmore.c @@ -328,6 +328,7 @@ xlockmore_screenhack (Display *dpy, Window window, do { hack_draw (&mi); XSync(dpy, False); + screenhack_handle_events (dpy); if (mi.pause) usleep(mi.pause); mi.pause = orig_pause; diff --git a/hacks/xlyap.c b/hacks/xlyap.c index 7557dce3..b180fc43 100644 --- a/hacks/xlyap.c +++ b/hacks/xlyap.c @@ -582,6 +582,9 @@ main_event(void) break; case ButtonRelease: EndRubberBand(canvas, &rubber_data, &event); + break; + default: + screenhack_handle_event (dpy, &event); break; } } diff --git a/hacks/xroger-hack.c b/hacks/xroger-hack.c index 278189c5..f4fa1164 100644 --- a/hacks/xroger-hack.c +++ b/hacks/xroger-hack.c @@ -73,7 +73,8 @@ screenhack (dpy, window) 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); diff --git a/setup.com b/setup.com index d6d2d1e0..b32920af 100644 --- a/setup.com +++ b/setup.com @@ -61,6 +61,7 @@ $ rotor :== $'mydir'rotor $ sierpinski :== $'mydir'sierpinski $ slidescreen :== $'mydir'slidescreen $ slip :== $'mydir'slip +$ sonar :== $'mydir'sonar $ sphere :== $'mydir'sphere $ spiral :== $'mydir'spiral $ starfish :== $'mydir'starfish diff --git a/utils/version.h b/utils/version.h index 4b67aa21..0ef8295f 100644 --- a/utils/version.h +++ b/utils/version.h @@ -1,2 +1,2 @@ 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)"; diff --git a/xscreensaver.lsm b/xscreensaver.lsm index f74c3920..babdbccb 100644 --- a/xscreensaver.lsm +++ b/xscreensaver.lsm @@ -1,7 +1,7 @@ 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. @@ -10,16 +10,16 @@ Keywords: screen saver, screen lock, lock, xlock, X11 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. diff --git a/xscreensaver.spec b/xscreensaver.spec index c31c1ad1..89dd6d91 100644 --- a/xscreensaver.spec +++ b/xscreensaver.spec @@ -1,7 +1,7 @@ Name: xscreensaver Summary: X screen saver and locker -Vendor: Jamie Zawinski -Version: 3.04 +Vendor: Jamie Zawinski +Version: 3.06 Release: 1 URL: http://www.jwz.org/xscreensaver/ Source: xscreensaver-%{version}.tar.gz -- 2.30.2