b4light.c revision 44d7874b
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/Xaw/Label.h>
36#include <X11/Xaw/Cardinals.h>
37#include <X11/extensions/scrnsaver.h>
38#include <X11/Xcms.h>
39#include <stdlib.h>
40#include <time.h>
41
42#ifdef NOTDEF
43static void quit (Widget w, XEvent *event,
44		  String *params, Cardinal *num_params);
45
46static XtActionsRec beforedark_actions[] = {
47    { "quit",	quit },
48};
49
50static Atom wm_delete_window;
51#endif
52
53static int  ss_event, ss_error;
54
55static Display *display;
56static Window  root, saver;
57static int screen;
58static int  scr_wid, scr_hei;
59static Colormap	cmap;
60static GC gc, black_gc, erase_gc;
61static int  screen_saved;
62static XtAppContext app_con;
63static GC   bit_1_gc, bit_0_gc;
64static Bool	filled = False;
65
66#define MAX_POINTS  16
67
68typedef  struct _moving {
69    int  x, y, dx, dy;
70} Moving;
71
72static Moving	p[MAX_POINTS];
73
74#define NUM_HISTORY 32
75
76static XPoint	history[NUM_HISTORY][MAX_POINTS];
77static Pixmap	old_pixmaps[NUM_HISTORY];
78static unsigned long	old_pixels[NUM_HISTORY];
79static int	num_points = 3;
80static int	history_head, history_tail;
81#define hist_bump(h)	((++(h) == NUM_HISTORY) ? ((h) = 0) : 0)
82
83#define NUM_COLORS  64
84
85static unsigned long	black_pixel;
86static unsigned long	pixels[NUM_COLORS];
87static int  cur_pen = 0;
88
89static void
90AllocateColors (void)
91{
92    double	angle;
93    double	step;
94    XcmsColor	cms_color;
95    int		i;
96    XColor	hard, exact;
97
98    XAllocNamedColor (display, cmap, "black", &hard, &exact);
99    black_pixel = hard.pixel;
100    step = 360.0 / NUM_COLORS;
101    for (i = 0; i < NUM_COLORS; i++) {
102	angle = i * step;
103	cms_color.spec.TekHVC.H = angle;
104	cms_color.spec.TekHVC.V = 75.0;
105	cms_color.spec.TekHVC.C = 75.0;
106	cms_color.format = XcmsTekHVCFormat;
107	XcmsAllocColor (display, cmap, &cms_color, XcmsRGBFormat);
108	pixels[i] = cms_color.pixel;
109    }
110}
111
112
113static void
114StepPen (void)
115{
116    XSetForeground (display, gc, pixels[cur_pen]);
117    cur_pen++;
118    if (cur_pen == NUM_COLORS)
119	cur_pen = 0;
120}
121
122static void
123DrawPoints (Drawable draw, GC gc, XPoint *p, int n)
124{
125    XPoint  xp[MAX_POINTS + 1];
126    int	    i;
127
128    switch (n) {
129    case 1:
130	XDrawPoint (display, draw, gc, p->x, p->y);
131	break;
132    case 2:
133	XDrawLine (display, draw, gc, p[0].x, p[0].y, p[1].x, p[1].y);
134	break;
135    default:
136	for (i = 0; i < n; i++) {
137	    xp[i].x = p[i].x; xp[i].y = p[i].y;
138	}
139	xp[i].x = p[0].x; xp[i].y = p[0].y;
140	if (filled)
141	    XFillPolygon (display, draw, gc, xp, i+1, Complex, CoordModeOrigin);
142	else
143	    XDrawLines (display, draw, gc, xp, i + 1, CoordModeOrigin);
144    }
145}
146
147static void
148Draw (Moving *p, int n)
149{
150    XPoint  xp[MAX_POINTS];
151    int	    i;
152    for (i = 0; i < n; i++)
153    {
154	xp[i].x = p[i].x; xp[i].y = p[i].y;
155    }
156    old_pixels[history_head] = pixels[cur_pen];
157    StepPen ();
158    DrawPoints (saver, gc, xp, n);
159    if (filled)
160    {
161	XFillRectangle (display, old_pixmaps[history_head], bit_0_gc,
162			0, 0, scr_wid, scr_hei);
163	DrawPoints (old_pixmaps[history_head], bit_1_gc, xp, n);
164	for (i = history_tail; i != history_head; hist_bump(i))
165	    DrawPoints (old_pixmaps[i], bit_0_gc, xp, n);
166    }
167}
168
169static void
170Erase (XPoint *p, int n)
171{
172    if (filled) {
173	XSetForeground (display, erase_gc, black_pixel ^ old_pixels[history_tail]);
174	XCopyPlane (display, old_pixmaps[history_tail], saver, erase_gc,
175		    0, 0, scr_wid, scr_hei, 0, 0, 1);
176    }
177    else
178	DrawPoints (saver, black_gc, p, n);
179}
180
181#define STEP_MAX    32
182
183static int
184RandomStep (void)
185{
186    return (rand () % STEP_MAX) + 1;
187}
188
189static void
190StepMoving (Moving *m)
191{
192    int	maxx, maxy;
193
194    maxx = DisplayWidth (display, screen);
195    maxy = DisplayHeight (display, screen);
196    m->x += m->dx;
197    if (m->x <= 0) {
198	m->x = 0;
199	m->dx = RandomStep ();
200    }
201    if (m->x >= maxx) {
202	m->x = maxx - 1;
203	m->dx = -RandomStep ();
204    }
205    m->y += m->dy;
206    if (m->y <= 0) {
207	m->y = 0;
208	m->dy = RandomStep ();
209    }
210    if (m->y >= maxy) {
211	m->y = maxy - 1;
212	m->dy = -RandomStep ();
213    }
214}
215
216static void
217StepPoints (void)
218{
219    int	i;
220
221    for (i = 0; i < num_points; i++)
222	StepMoving (&p[i]);
223    hist_bump(history_head);
224    if (history_tail == history_head)
225    {
226	Erase (history[history_tail], num_points);
227	hist_bump(history_tail);
228    }
229    Draw (p, num_points);
230    for (i = 0; i < num_points; i++)
231    {
232    	history[history_head][i].x = p[i].x;
233    	history[history_head][i].y = p[i].y;
234    }
235}
236
237static void
238StartPoints (void)
239{
240    history_head = history_tail = 0;
241}
242
243static void
244Timeout (XtPointer closure, XtIntervalId *id)
245{
246    if (screen_saved)
247    {
248	StepPoints ();
249	(void) XtAppAddTimeOut (app_con, 50, Timeout, NULL);
250    }
251}
252
253static void
254StartSaver (void)
255{
256    if (screen_saved)
257	return;
258    screen_saved = True;
259    StartPoints ();
260    StepPoints ();
261    (void) XtAppAddTimeOut (app_con, 50, Timeout, NULL);
262}
263
264static void
265StopSaver (void)
266{
267    if (!screen_saved)
268	return;
269    screen_saved = False;
270}
271
272static int
273ignoreError (Display *display, XErrorEvent *error)
274{
275    return 0;
276}
277
278int
279main(int argc, char *argv[])
280{
281    Widget toplevel;
282    XEvent  event;
283    XScreenSaverNotifyEvent *sevent;
284    XSetWindowAttributes    attr;
285    XScreenSaverInfo	    *info;
286    unsigned long	    mask;
287    Pixmap		    blank_pix;
288    XColor		    dummyColor;
289    XID			    kill_id;
290    Atom		    kill_type;
291    int			    i;
292    int			    (*oldHandler)();
293    Window 		    r;
294    int			    x, y;
295    unsigned int	    w, h, b, d;
296    Status		    s;
297
298#if !defined(X_NOT_POSIX)
299    srand((int)time((time_t *)NULL));
300#else
301    srand((int)time((int *)NULL));
302#endif
303
304    toplevel = XtAppInitialize (&app_con, "Beforelight", NULL, ZERO,
305				&argc, argv, NULL, NULL, ZERO);
306    display = XtDisplay (toplevel);
307    root = DefaultRootWindow (display);
308    screen = DefaultScreen (display);
309    scr_wid = DisplayWidth (display, screen);
310    scr_hei = DisplayHeight (display, screen);
311    if (!XScreenSaverQueryExtension (display, &ss_event, &ss_error))
312	exit (1);
313#ifdef NOTDEF
314    XtAppAddActions (app_con, beforedark_actions, XtNumber(beforedark_actions));
315
316    /*
317     * This is a hack so that f.delete will do something useful in this
318     * single-window application.
319     */
320    XtOverrideTranslations(toplevel,
321		    XtParseTranslationTable ("<Message>WM_PROTOCOLS: quit()"));
322
323    XtCreateManagedWidget ("label", labelWidgetClass, toplevel, NULL, ZERO);
324    XtRealizeWidget (toplevel);
325    wm_delete_window = XInternAtom (XtDisplay(toplevel), "WM_DELETE_WINDOW",
326				    False);
327    (void) XSetWMProtocols (XtDisplay(toplevel), XtWindow(toplevel),
328			    &wm_delete_window, 1);
329
330#endif
331    oldHandler = XSetErrorHandler (ignoreError);
332    if (XScreenSaverGetRegistered (display, screen, &kill_id, &kill_type)) {
333	s = XGetGeometry(display, kill_id, &r, &x, &y, &w, &h, &b, &d);
334	if (s == True && r == root && w == 1 && h == 1 && d == 1) {
335	    /* Try to clean up existing saver & resources */
336	    XKillClient (display, kill_id);
337	    XScreenSaverUnregister(display, screen);
338	}
339    }
340    XSync(display, FALSE);
341    XSetErrorHandler(oldHandler);
342    XScreenSaverSelectInput (display, root, ScreenSaverNotifyMask);
343#ifdef NOTDEF
344    cmap = XCreateColormap (display, root, DefaultVisual (display, screen), AllocNone);
345#else
346    cmap = DefaultColormap (display, screen);
347#endif
348    AllocateColors();
349    blank_pix = XCreatePixmap (display, root, 1, 1, 1);
350    XScreenSaverRegister (display, screen, (XID) blank_pix, XA_PIXMAP);
351    bit_0_gc = XCreateGC (display, blank_pix, 0, 0);
352    XSetForeground (display, bit_0_gc, 0);
353    bit_1_gc = XCreateGC (display, blank_pix, 0, 0);
354    XSetForeground (display, bit_1_gc, ~0);
355    XFillRectangle (display, blank_pix, bit_0_gc, 0, 0, 1, 1);
356    info = XScreenSaverAllocInfo ();
357    XScreenSaverQueryInfo (display, root, info);
358    mask = 0;
359    attr.colormap = cmap;
360    mask |= CWColormap;
361    attr.background_pixel = black_pixel;
362    mask |= CWBackPixel;
363    attr.cursor = XCreatePixmapCursor (display, blank_pix, blank_pix, &dummyColor, &dummyColor, 0, 0);
364    mask |= CWCursor;
365    XScreenSaverSetAttributes (display, root, 0, 0,
366	DisplayWidth (display, screen), DisplayHeight(display, screen), 0,
367	CopyFromParent, CopyFromParent, CopyFromParent, mask, &attr);
368    XSync (display, False);
369    gc = XCreateGC (display, root, 0, 0);
370    black_gc = XCreateGC (display, root, 0, 0);
371    XSetForeground (display, black_gc, black_pixel);
372    if (filled)
373    {
374    	erase_gc = XCreateGC (display, root, 0, 0);
375    	XSetBackground (display, erase_gc, 0);
376    	XSetFunction (display, erase_gc, GXxor);
377    	XSetGraphicsExposures (display, erase_gc, False);
378    	for (i = 0; i < NUM_HISTORY; i++)
379	    old_pixmaps[i] = XCreatePixmap (display, root, scr_wid, scr_hei, 1);
380    }
381    XSetErrorHandler (ignoreError);
382    saver = info->window;
383    if (info->state == ScreenSaverOn)
384    {
385	if (info->kind != ScreenSaverExternal)
386	{
387	    XResetScreenSaver (display);
388	    XActivateScreenSaver (display);
389	}
390	StartSaver ();
391    }
392    for (;;)
393    {
394	XtAppNextEvent (app_con, &event);
395	if (event.type == ss_event) {
396	    sevent = (XScreenSaverNotifyEvent *) &event;
397	    if (sevent->state == ScreenSaverOn) {
398		if (sevent->kind != ScreenSaverExternal) {
399	    	    XResetScreenSaver (display);
400	    	    XActivateScreenSaver (display);
401		} else {
402		    StartSaver ();
403		}
404	    } else if (sevent->state == ScreenSaverOff) {
405		StopSaver ();
406	    }
407	} else {
408	    XtDispatchEvent(&event);
409	}
410    }
411}
412
413#ifdef NOTDEF
414static void
415quit (Widget w, XEvent *event, String *params, Cardinal *num_params)
416{
417    if (event->type == ClientMessage &&
418	event->xclient.data.l[0] != wm_delete_window) {
419	XBell (XtDisplay(w), 0);
420	return;
421    }
422    XCloseDisplay (XtDisplay(w));
423    exit (0);
424}
425#endif
426