b4light.c revision e9feffd0
1/*
2 * $XConsortium: b4light.c,v 1.3 94/04/17 20:59:38 rws Exp $
3 *
4Copyright (c) 1992  X Consortium
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in
14all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the name of the X Consortium shall not be
24used in advertising or otherwise to promote the sale, use or other dealings
25in this Software without prior written authorization from the X Consortium.
26 *
27 * Author:  Keith Packard, MIT X Consortium
28 */
29/* $XFree86: xc/programs/beforelight/b4light.c,v 3.6tsi Exp $ */
30
31#include <X11/Xatom.h>
32#include <X11/Intrinsic.h>
33#include <X11/StringDefs.h>
34#include <X11/Shell.h>
35#include <X11/extensions/scrnsaver.h>
36#include <X11/Xcms.h>
37#include <stdlib.h>
38#include <time.h>
39
40#ifndef ZERO
41# define ZERO ((Cardinal)0)
42#endif
43
44
45static int  ss_event, ss_error;
46
47static Display *display;
48static Window  root, saver;
49static int screen;
50static int  scr_wid, scr_hei;
51static Colormap	cmap;
52static GC gc, black_gc, erase_gc;
53static int  screen_saved;
54static XtAppContext app_con;
55static GC   bit_1_gc, bit_0_gc;
56static Bool	filled = False;
57
58#define MAX_POINTS  16
59
60typedef  struct _moving {
61    int  x, y, dx, dy;
62} Moving;
63
64static Moving	p[MAX_POINTS];
65
66#define NUM_HISTORY 32
67
68static XPoint	history[NUM_HISTORY][MAX_POINTS];
69static Pixmap	old_pixmaps[NUM_HISTORY];
70static unsigned long	old_pixels[NUM_HISTORY];
71static int	num_points = 3;
72static int	history_head, history_tail;
73#define hist_bump(h)	((++(h) == NUM_HISTORY) ? ((h) = 0) : 0)
74
75#define NUM_COLORS  64
76
77static unsigned long	black_pixel;
78static unsigned long	pixels[NUM_COLORS];
79static int  cur_pen = 0;
80
81static void
82AllocateColors (void)
83{
84    double	angle;
85    double	step;
86    XcmsColor	cms_color;
87    int		i;
88    XColor	hard, exact;
89
90    XAllocNamedColor (display, cmap, "black", &hard, &exact);
91    black_pixel = hard.pixel;
92    step = 360.0 / NUM_COLORS;
93    for (i = 0; i < NUM_COLORS; i++) {
94	angle = i * step;
95	cms_color.spec.TekHVC.H = angle;
96	cms_color.spec.TekHVC.V = 75.0;
97	cms_color.spec.TekHVC.C = 75.0;
98	cms_color.format = XcmsTekHVCFormat;
99	XcmsAllocColor (display, cmap, &cms_color, XcmsRGBFormat);
100	pixels[i] = cms_color.pixel;
101    }
102}
103
104
105static void
106StepPen (void)
107{
108    XSetForeground (display, gc, pixels[cur_pen]);
109    cur_pen++;
110    if (cur_pen == NUM_COLORS)
111	cur_pen = 0;
112}
113
114static void
115DrawPoints (Drawable draw, GC draw_gc, XPoint *pt, int n)
116{
117    XPoint  xp[MAX_POINTS + 1];
118    int	    i;
119
120    switch (n) {
121    case 1:
122	XDrawPoint (display, draw, draw_gc, pt->x, pt->y);
123	break;
124    case 2:
125	XDrawLine (display, draw, draw_gc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
126	break;
127    default:
128	for (i = 0; i < n; i++) {
129	    xp[i].x = pt[i].x; xp[i].y = pt[i].y;
130	}
131	xp[i].x = pt[0].x; xp[i].y = pt[0].y;
132	if (filled)
133	    XFillPolygon (display, draw, draw_gc, xp, i+1, Complex, CoordModeOrigin);
134	else
135	    XDrawLines (display, draw, draw_gc, xp, i + 1, CoordModeOrigin);
136    }
137}
138
139static void
140Draw (Moving *mp, int n)
141{
142    XPoint  xp[MAX_POINTS];
143    int	    i;
144    for (i = 0; i < n; i++)
145    {
146	xp[i].x = mp[i].x; xp[i].y = mp[i].y;
147    }
148    old_pixels[history_head] = pixels[cur_pen];
149    StepPen ();
150    DrawPoints (saver, gc, xp, n);
151    if (filled)
152    {
153	XFillRectangle (display, old_pixmaps[history_head], bit_0_gc,
154			0, 0, scr_wid, scr_hei);
155	DrawPoints (old_pixmaps[history_head], bit_1_gc, xp, n);
156	for (i = history_tail; i != history_head; hist_bump(i))
157	    DrawPoints (old_pixmaps[i], bit_0_gc, xp, n);
158    }
159}
160
161static void
162Erase (XPoint *pt, int n)
163{
164    if (filled) {
165	XSetForeground (display, erase_gc, black_pixel ^ old_pixels[history_tail]);
166	XCopyPlane (display, old_pixmaps[history_tail], saver, erase_gc,
167		    0, 0, scr_wid, scr_hei, 0, 0, 1);
168    }
169    else
170	DrawPoints (saver, black_gc, pt, n);
171}
172
173#define STEP_MAX    32
174
175static int
176RandomStep (void)
177{
178    return (rand () % STEP_MAX) + 1;
179}
180
181static void
182StepMoving (Moving *m)
183{
184    int	maxx, maxy;
185
186    maxx = DisplayWidth (display, screen);
187    maxy = DisplayHeight (display, screen);
188    m->x += m->dx;
189    if (m->x <= 0) {
190	m->x = 0;
191	m->dx = RandomStep ();
192    }
193    if (m->x >= maxx) {
194	m->x = maxx - 1;
195	m->dx = -RandomStep ();
196    }
197    m->y += m->dy;
198    if (m->y <= 0) {
199	m->y = 0;
200	m->dy = RandomStep ();
201    }
202    if (m->y >= maxy) {
203	m->y = maxy - 1;
204	m->dy = -RandomStep ();
205    }
206}
207
208static void
209StepPoints (void)
210{
211    int	i;
212
213    for (i = 0; i < num_points; i++)
214	StepMoving (&p[i]);
215    hist_bump(history_head);
216    if (history_tail == history_head)
217    {
218	Erase (history[history_tail], num_points);
219	hist_bump(history_tail);
220    }
221    Draw (p, num_points);
222    for (i = 0; i < num_points; i++)
223    {
224    	history[history_head][i].x = p[i].x;
225    	history[history_head][i].y = p[i].y;
226    }
227}
228
229static void
230StartPoints (void)
231{
232    history_head = history_tail = 0;
233}
234
235static void
236Timeout (XtPointer closure, XtIntervalId *id)
237{
238    if (screen_saved)
239    {
240	StepPoints ();
241	(void) XtAppAddTimeOut (app_con, 50, Timeout, NULL);
242    }
243}
244
245static void
246StartSaver (void)
247{
248    if (screen_saved)
249	return;
250    screen_saved = True;
251    StartPoints ();
252    StepPoints ();
253    (void) XtAppAddTimeOut (app_con, 50, Timeout, NULL);
254}
255
256static void
257StopSaver (void)
258{
259    if (!screen_saved)
260	return;
261    screen_saved = False;
262}
263
264static int
265ignoreError (Display *dpy, XErrorEvent *error)
266{
267    return 0;
268}
269
270int
271main(int argc, char *argv[])
272{
273    Widget toplevel;
274    XEvent  event;
275    XScreenSaverNotifyEvent *sevent;
276    XSetWindowAttributes    attr;
277    XScreenSaverInfo	    *info;
278    unsigned long	    mask;
279    Pixmap		    blank_pix;
280    XColor		    dummyColor;
281    XID			    kill_id;
282    Atom		    kill_type;
283    int			    i;
284    int			    (*oldHandler)(Display*, XErrorEvent*);
285    Window 		    r;
286    int			    x, y;
287    unsigned int	    w, h, b, d;
288    Status		    s;
289
290    srand((int)time((time_t *)NULL));
291
292    toplevel = XtAppInitialize (&app_con, "Beforelight", NULL, ZERO,
293				&argc, argv, NULL, NULL, ZERO);
294    display = XtDisplay (toplevel);
295    root = DefaultRootWindow (display);
296    screen = DefaultScreen (display);
297    scr_wid = DisplayWidth (display, screen);
298    scr_hei = DisplayHeight (display, screen);
299    if (!XScreenSaverQueryExtension (display, &ss_event, &ss_error))
300	exit (1);
301    oldHandler = XSetErrorHandler (ignoreError);
302    if (XScreenSaverGetRegistered (display, screen, &kill_id, &kill_type)) {
303	s = XGetGeometry(display, kill_id, &r, &x, &y, &w, &h, &b, &d);
304	if (s == True && r == root && w == 1 && h == 1 && d == 1) {
305	    /* Try to clean up existing saver & resources */
306	    XKillClient (display, kill_id);
307	    XScreenSaverUnregister(display, screen);
308	}
309    }
310    XSync(display, FALSE);
311    XSetErrorHandler(oldHandler);
312    XScreenSaverSelectInput (display, root, ScreenSaverNotifyMask);
313    cmap = DefaultColormap (display, screen);
314    AllocateColors();
315    blank_pix = XCreatePixmap (display, root, 1, 1, 1);
316    XScreenSaverRegister (display, screen, (XID) blank_pix, XA_PIXMAP);
317    bit_0_gc = XCreateGC (display, blank_pix, 0, NULL);
318    XSetForeground (display, bit_0_gc, 0);
319    bit_1_gc = XCreateGC (display, blank_pix, 0, NULL);
320    XSetForeground (display, bit_1_gc, ~0);
321    XFillRectangle (display, blank_pix, bit_0_gc, 0, 0, 1, 1);
322    info = XScreenSaverAllocInfo ();
323    XScreenSaverQueryInfo (display, root, info);
324    mask = 0;
325    attr.colormap = cmap;
326    mask |= CWColormap;
327    attr.background_pixel = black_pixel;
328    mask |= CWBackPixel;
329    attr.cursor = XCreatePixmapCursor (display, blank_pix, blank_pix, &dummyColor, &dummyColor, 0, 0);
330    mask |= CWCursor;
331    XScreenSaverSetAttributes (display, root, 0, 0,
332	DisplayWidth (display, screen), DisplayHeight(display, screen), 0,
333	CopyFromParent, CopyFromParent, (Visual *)CopyFromParent, mask, &attr);
334    XSync (display, False);
335    gc = XCreateGC (display, root, 0, NULL);
336    black_gc = XCreateGC (display, root, 0, NULL);
337    XSetForeground (display, black_gc, black_pixel);
338    if (filled)
339    {
340    	erase_gc = XCreateGC (display, root, 0, NULL);
341    	XSetBackground (display, erase_gc, 0);
342    	XSetFunction (display, erase_gc, GXxor);
343    	XSetGraphicsExposures (display, erase_gc, False);
344    	for (i = 0; i < NUM_HISTORY; i++)
345	    old_pixmaps[i] = XCreatePixmap (display, root, scr_wid, scr_hei, 1);
346    }
347    XSetErrorHandler (ignoreError);
348    saver = info->window;
349    if (info->state == ScreenSaverOn)
350    {
351	if (info->kind != ScreenSaverExternal)
352	{
353	    XResetScreenSaver (display);
354	    XActivateScreenSaver (display);
355	}
356	StartSaver ();
357    }
358    for (;;)
359    {
360	XtAppNextEvent (app_con, &event);
361	if (event.type == ss_event) {
362	    sevent = (XScreenSaverNotifyEvent *) &event;
363	    if (sevent->state == ScreenSaverOn) {
364		if (sevent->kind != ScreenSaverExternal) {
365	    	    XResetScreenSaver (display);
366	    	    XActivateScreenSaver (display);
367		} else {
368		    StartSaver ();
369		}
370	    } else if (sevent->state == ScreenSaverOff) {
371		StopSaver ();
372	    }
373	} else {
374	    XtDispatchEvent(&event);
375	}
376    }
377}
378
379