#include <X11/Xatom.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/extensions/scrnsaver.h>
#include <X11/Xcms.h>
#include <stdlib.h>
#include <time.h>
#ifdef NOTDEF
static void quit (Widget w, XEvent *event,
String *params, Cardinal *num_params);
static XtActionsRec beforedark_actions[] = {
{ "quit", quit },
};
static Atom wm_delete_window;
#endif
static int ss_event, ss_error;
static Display *display;
static Window root, saver;
static int screen;
static int scr_wid, scr_hei;
static Colormap cmap;
static GC gc, black_gc, erase_gc;
static int screen_saved;
static XtAppContext app_con;
static GC bit_1_gc, bit_0_gc;
static Bool filled = False;
#define MAX_POINTS 16
typedef struct _moving {
int x, y, dx, dy;
} Moving;
static Moving p[MAX_POINTS];
#define NUM_HISTORY 32
static XPoint history[NUM_HISTORY][MAX_POINTS];
static Pixmap old_pixmaps[NUM_HISTORY];
static unsigned long old_pixels[NUM_HISTORY];
static int num_points = 3;
static int history_head, history_tail;
#define hist_bump(h) ((++(h) == NUM_HISTORY) ? ((h) = 0) : 0)
#define NUM_COLORS 64
static unsigned long black_pixel;
static unsigned long pixels[NUM_COLORS];
static int cur_pen = 0;
static void
AllocateColors (void)
{
double angle;
double step;
XcmsColor cms_color;
int i;
XColor hard, exact;
XAllocNamedColor (display, cmap, "black", &hard, &exact);
black_pixel = hard.pixel;
step = 360.0 / NUM_COLORS;
for (i = 0; i < NUM_COLORS; i++) {
angle = i * step;
cms_color.spec.TekHVC.H = angle;
cms_color.spec.TekHVC.V = 75.0;
cms_color.spec.TekHVC.C = 75.0;
cms_color.format = XcmsTekHVCFormat;
XcmsAllocColor (display, cmap, &cms_color, XcmsRGBFormat);
pixels[i] = cms_color.pixel;
}
}
static void
StepPen (void)
{
XSetForeground (display, gc, pixels[cur_pen]);
cur_pen++;
if (cur_pen == NUM_COLORS)
cur_pen = 0;
}
static void
DrawPoints (Drawable draw, GC gc, XPoint *p, int n)
{
XPoint xp[MAX_POINTS + 1];
int i;
switch (n) {
case 1:
XDrawPoint (display, draw, gc, p->x, p->y);
break;
case 2:
XDrawLine (display, draw, gc, p[0].x, p[0].y, p[1].x, p[1].y);
break;
default:
for (i = 0; i < n; i++) {
xp[i].x = p[i].x; xp[i].y = p[i].y;
}
xp[i].x = p[0].x; xp[i].y = p[0].y;
if (filled)
XFillPolygon (display, draw, gc, xp, i+1, Complex, CoordModeOrigin);
else
XDrawLines (display, draw, gc, xp, i + 1, CoordModeOrigin);
}
}
static void
Draw (Moving *p, int n)
{
XPoint xp[MAX_POINTS];
int i;
for (i = 0; i < n; i++)
{
xp[i].x = p[i].x; xp[i].y = p[i].y;
}
old_pixels[history_head] = pixels[cur_pen];
StepPen ();
DrawPoints (saver, gc, xp, n);
if (filled)
{
XFillRectangle (display, old_pixmaps[history_head], bit_0_gc,
0, 0, scr_wid, scr_hei);
DrawPoints (old_pixmaps[history_head], bit_1_gc, xp, n);
for (i = history_tail; i != history_head; hist_bump(i))
DrawPoints (old_pixmaps[i], bit_0_gc, xp, n);
}
}
static void
Erase (XPoint *p, int n)
{
if (filled) {
XSetForeground (display, erase_gc, black_pixel ^ old_pixels[history_tail]);
XCopyPlane (display, old_pixmaps[history_tail], saver, erase_gc,
0, 0, scr_wid, scr_hei, 0, 0, 1);
}
else
DrawPoints (saver, black_gc, p, n);
}
#define STEP_MAX 32
static int
RandomStep (void)
{
return (rand () % STEP_MAX) + 1;
}
static void
StepMoving (Moving *m)
{
int maxx, maxy;
maxx = DisplayWidth (display, screen);
maxy = DisplayHeight (display, screen);
m->x += m->dx;
if (m->x <= 0) {
m->x = 0;
m->dx = RandomStep ();
}
if (m->x >= maxx) {
m->x = maxx - 1;
m->dx = -RandomStep ();
}
m->y += m->dy;
if (m->y <= 0) {
m->y = 0;
m->dy = RandomStep ();
}
if (m->y >= maxy) {
m->y = maxy - 1;
m->dy = -RandomStep ();
}
}
static void
StepPoints (void)
{
int i;
for (i = 0; i < num_points; i++)
StepMoving (&p[i]);
hist_bump(history_head);
if (history_tail == history_head)
{
Erase (history[history_tail], num_points);
hist_bump(history_tail);
}
Draw (p, num_points);
for (i = 0; i < num_points; i++)
{
history[history_head][i].x = p[i].x;
history[history_head][i].y = p[i].y;
}
}
static void
StartPoints (void)
{
history_head = history_tail = 0;
}
static void
Timeout (XtPointer closure, XtIntervalId *id)
{
if (screen_saved)
{
StepPoints ();
(void) XtAppAddTimeOut (app_con, 50, Timeout, NULL);
}
}
static void
StartSaver (void)
{
if (screen_saved)
return;
screen_saved = True;
StartPoints ();
StepPoints ();
(void) XtAppAddTimeOut (app_con, 50, Timeout, NULL);
}
static void
StopSaver (void)
{
if (!screen_saved)
return;
screen_saved = False;
}
static int
ignoreError (Display *display, XErrorEvent *error)
{
return 0;
}
int
main(int argc, char *argv[])
{
Widget toplevel;
XEvent event;
XScreenSaverNotifyEvent *sevent;
XSetWindowAttributes attr;
XScreenSaverInfo *info;
unsigned long mask;
Pixmap blank_pix;
XColor dummyColor;
XID kill_id;
Atom kill_type;
int i;
int (*oldHandler)();
Window r;
int x, y;
unsigned int w, h, b, d;
Status s;
#if !defined(X_NOT_POSIX)
srand((int)time((time_t *)NULL));
#else
srand((int)time((int *)NULL));
#endif
toplevel = XtAppInitialize (&app_con, "Beforelight", NULL, ZERO,
&argc, argv, NULL, NULL, ZERO);
display = XtDisplay (toplevel);
root = DefaultRootWindow (display);
screen = DefaultScreen (display);
scr_wid = DisplayWidth (display, screen);
scr_hei = DisplayHeight (display, screen);
if (!XScreenSaverQueryExtension (display, &ss_event, &ss_error))
exit (1);
#ifdef NOTDEF
XtAppAddActions (app_con, beforedark_actions, XtNumber(beforedark_actions));
XtOverrideTranslations(toplevel,
XtParseTranslationTable ("<Message>WM_PROTOCOLS: quit()"));
XtCreateManagedWidget ("label", labelWidgetClass, toplevel, NULL, ZERO);
XtRealizeWidget (toplevel);
wm_delete_window = XInternAtom (XtDisplay(toplevel), "WM_DELETE_WINDOW",
False);
(void) XSetWMProtocols (XtDisplay(toplevel), XtWindow(toplevel),
&wm_delete_window, 1);
#endif
oldHandler = XSetErrorHandler (ignoreError);
if (XScreenSaverGetRegistered (display, screen, &kill_id, &kill_type)) {
s = XGetGeometry(display, kill_id, &r, &x, &y, &w, &h, &b, &d);
if (s == True && r == root && w == 1 && h == 1 && d == 1) {
XKillClient (display, kill_id);
XScreenSaverUnregister(display, screen);
}
}
XSync(display, FALSE);
XSetErrorHandler(oldHandler);
XScreenSaverSelectInput (display, root, ScreenSaverNotifyMask);
#ifdef NOTDEF
cmap = XCreateColormap (display, root, DefaultVisual (display, screen), AllocNone);
#else
cmap = DefaultColormap (display, screen);
#endif
AllocateColors();
blank_pix = XCreatePixmap (display, root, 1, 1, 1);
XScreenSaverRegister (display, screen, (XID) blank_pix, XA_PIXMAP);
bit_0_gc = XCreateGC (display, blank_pix, 0, 0);
XSetForeground (display, bit_0_gc, 0);
bit_1_gc = XCreateGC (display, blank_pix, 0, 0);
XSetForeground (display, bit_1_gc, ~0);
XFillRectangle (display, blank_pix, bit_0_gc, 0, 0, 1, 1);
info = XScreenSaverAllocInfo ();
XScreenSaverQueryInfo (display, root, info);
mask = 0;
attr.colormap = cmap;
mask |= CWColormap;
attr.background_pixel = black_pixel;
mask |= CWBackPixel;
attr.cursor = XCreatePixmapCursor (display, blank_pix, blank_pix, &dummyColor, &dummyColor, 0, 0);
mask |= CWCursor;
XScreenSaverSetAttributes (display, root, 0, 0,
DisplayWidth (display, screen), DisplayHeight(display, screen), 0,
CopyFromParent, CopyFromParent, CopyFromParent, mask, &attr);
XSync (display, False);
gc = XCreateGC (display, root, 0, 0);
black_gc = XCreateGC (display, root, 0, 0);
XSetForeground (display, black_gc, black_pixel);
if (filled)
{
erase_gc = XCreateGC (display, root, 0, 0);
XSetBackground (display, erase_gc, 0);
XSetFunction (display, erase_gc, GXxor);
XSetGraphicsExposures (display, erase_gc, False);
for (i = 0; i < NUM_HISTORY; i++)
old_pixmaps[i] = XCreatePixmap (display, root, scr_wid, scr_hei, 1);
}
XSetErrorHandler (ignoreError);
saver = info->window;
if (info->state == ScreenSaverOn)
{
if (info->kind != ScreenSaverExternal)
{
XResetScreenSaver (display);
XActivateScreenSaver (display);
}
StartSaver ();
}
for (;;)
{
XtAppNextEvent (app_con, &event);
if (event.type == ss_event) {
sevent = (XScreenSaverNotifyEvent *) &event;
if (sevent->state == ScreenSaverOn) {
if (sevent->kind != ScreenSaverExternal) {
XResetScreenSaver (display);
XActivateScreenSaver (display);
} else {
StartSaver ();
}
} else if (sevent->state == ScreenSaverOff) {
StopSaver ();
}
} else {
XtDispatchEvent(&event);
}
}
}
#ifdef NOTDEF
static void
quit (Widget w, XEvent *event, String *params, Cardinal *num_params)
{
if (event->type == ClientMessage &&
event->xclient.data.l[0] != wm_delete_window) {
XBell (XtDisplay(w), 0);
return;
}
XCloseDisplay (XtDisplay(w));
exit (0);
}
#endif