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