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