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