251
251
/* Draw one step of the hack. Positions are cell coordinates. */
253
draw_step (CriticalSettings *settings,
254
Display *dpy, Window window, GC gc,
255
int pos, XPoint *history)
253
draw_step (struct state *st, GC gc, int pos)
257
int cell_size = settings->cell_size;
255
int cell_size = st->settings.cell_size;
258
256
int half = cell_size/2;
259
int old_pos = (pos + settings->trail - 1) % settings->trail;
257
int old_pos = (pos + st->settings.trail - 1) % st->settings.trail;
261
pos = pos % settings->trail;
259
pos = pos % st->settings.trail;
263
XDrawLine (dpy, window, gc,
264
history[pos].x * cell_size + half,
265
history[pos].y * cell_size + half,
266
history[old_pos].x * cell_size + half,
267
history[old_pos].y * cell_size + half);
261
XDrawLine (st->dpy, st->window, gc,
262
st->history[pos].x * cell_size + half,
263
st->history[pos].y * cell_size + half,
264
st->history[old_pos].x * cell_size + half,
265
st->history[old_pos].y * cell_size + half);
272
/* Display a self-organizing criticality screen hack. The program
273
runs indefinately on the root window. */
275
screenhack (Display *dpy, Window window)
271
critical_init (Display *dpy, Window window)
273
struct state *st = (struct state *) calloc (1, sizeof(*st));
279
274
int model_w, model_h;
280
CriticalModel *model;
281
int lines_per_color = 10;
285
XPoint *history; /* in cell coords */
290
XWindowAttributes wattr;
291
CriticalSettings settings;
293
/* Number of screens that should be drawn before reinitializing the
294
model, and count of the number of screens done so far. */
295
int n_restart, i_restart;
297
278
/* Find window attributes */
298
XGetWindowAttributes (dpy, window, &wattr);
300
batchcount = get_integer_resource ("batchcount", "Integer");
279
XGetWindowAttributes (st->dpy, st->window, &st->wattr);
281
st->batchcount = get_integer_resource (st->dpy, "batchcount", "Integer");
282
if (st->batchcount < 5)
285
st->lines_per_color = 10;
304
287
/* For the moment the model size is just fixed -- making it vary
305
288
with the screen size just makes the hack boring on large
308
settings.cell_size = wattr.width / model_w;
309
model_h = wattr.height / settings.cell_size;
291
st->settings.cell_size = st->wattr.width / model_w;
292
model_h = st->settings.cell_size ?
293
st->wattr.height / st->settings.cell_size : 0;
311
295
/* Construct the initial model state. */
313
settings.trail = clip(2, get_integer_resource ("trail", "Integer"), 1000);
297
st->settings.trail = clip(2, get_integer_resource (st->dpy, "trail", "Integer"), 1000);
315
history = malloc (sizeof history[0] * settings.trail);
299
st->history = calloc (st->settings.trail, sizeof (st->history[0]));
318
302
fprintf (stderr, "critical: "
319
303
"couldn't allocate trail history of %d cells\n",
324
model = model_allocate (model_w, model_h);
308
st->model = model_allocate (model_w, model_h);
327
311
fprintf (stderr, "critical: error preparing the model\n");
331
315
/* make a black gc for the background */
332
gcv.foreground = get_pixel_resource ("background", "Background",
333
dpy, wattr.colormap);
334
bgc = XCreateGC (dpy, window, GCForeground, &gcv);
336
fgc = XCreateGC (dpy, window, 0, &gcv);
338
delay_usecs = get_integer_resource ("delay", "Integer");
339
n_restart = get_integer_resource ("restart", "Integer");
341
/* xscreensaver will kill or stop us when the user does something
342
* that deserves attention. */
350
/* Time to start a new simulation, this one has probably got
351
to be a bit boring. */
352
setup_colormap (dpy, &wattr, &colors, &n_colors);
353
erase_full_window (dpy, window);
354
model_initialize (model);
355
model_step (model, &history[0]);
360
for (i_batch = batchcount; i_batch; i_batch--)
363
if ((i_batch % lines_per_color) == 0)
365
i_color = (i_color + 1) % n_colors;
366
gcv.foreground = colors[i_color].pixel;
367
XChangeGC (dpy, fgc, GCForeground, &gcv);
370
assert(pos >= 0 && pos < settings.trail);
371
model_step (model, &history[pos]);
373
draw_step (&settings, dpy, window, fgc, pos, history);
375
/* we use the history as a ring buffer, but don't start erasing until
376
we've wrapped around once. */
377
if (++pos >= settings.trail)
379
pos -= settings.trail;
385
draw_step (&settings, dpy, window, bgc, pos+1, history);
389
screenhack_handle_events (dpy);
392
usleep (delay_usecs);
396
i_restart = (i_restart + 1) % n_restart;
400
/* Clean up after completing a simulation. */
401
free_colormap (dpy, &wattr, &colors, n_colors);
316
st->gcv.foreground = get_pixel_resource (st->dpy, st->wattr.colormap,
317
"background", "Background");
318
st->bgc = XCreateGC (st->dpy, st->window, GCForeground, &st->gcv);
320
st->fgc = XCreateGC (st->dpy, st->window, 0, &st->gcv);
323
jwxyz_XSetAntiAliasing (dpy, st->fgc, False);
324
jwxyz_XSetAntiAliasing (dpy, st->bgc, False);
327
st->delay_usecs = get_integer_resource (st->dpy, "delay", "Integer");
328
st->n_restart = get_integer_resource (st->dpy, "restart", "Integer");
330
setup_colormap (st, &st->d_colors, &st->d_n_colors);
331
model_initialize (st->model);
332
model_step (st->model, &st->history[0]);
336
st->d_i_batch = st->batchcount;
342
critical_draw (Display *dpy, Window window, void *closure)
344
struct state *st = (struct state *) closure;
347
st->eraser = erase_window (st->dpy, st->window, st->eraser);
348
return st->delay_usecs;
351
/* for (d_i_batch = batchcount; d_i_batch; d_i_batch--) */
354
if ((st->d_i_batch % st->lines_per_color) == 0)
356
st->d_i_color = (st->d_i_color + 1) % st->d_n_colors;
357
st->gcv.foreground = st->d_colors[st->d_i_color].pixel;
358
XChangeGC (st->dpy, st->fgc, GCForeground, &st->gcv);
361
assert(st->d_pos >= 0 && st->d_pos < st->settings.trail);
362
model_step (st->model, &st->history[st->d_pos]);
364
draw_step (st, st->fgc, st->d_pos);
366
/* we use the history as a ring buffer, but don't start erasing until
367
we've d_wrapped around once. */
368
if (++st->d_pos >= st->settings.trail)
370
st->d_pos -= st->settings.trail;
376
draw_step (st, st->bgc, st->d_pos+1);
382
if (st->d_i_batch < 0)
383
st->d_i_batch = st->batchcount;
385
return st->delay_usecs;
387
st->i_restart = (st->i_restart + 1) % st->n_restart;
389
if (st->i_restart == 0)
391
/* Time to start a new simulation, this one has probably got
392
to be a bit boring. */
393
free_colormap (st, &st->d_colors, st->d_n_colors);
394
setup_colormap (st, &st->d_colors, &st->d_n_colors);
395
st->eraser = erase_window (st->dpy, st->window, st->eraser);
396
model_initialize (st->model);
397
model_step (st->model, &st->history[0]);
400
st->d_i_batch = st->batchcount;
403
return st->delay_usecs;
407
critical_reshape (Display *dpy, Window window, void *closure,
408
unsigned int w, unsigned int h)
413
critical_event (Display *dpy, Window window, void *closure, XEvent *event)
419
critical_free (Display *dpy, Window window, void *closure)
421
struct state *st = (struct state *) closure;
426
/* Options this module understands. */
427
static XrmOptionDescRec critical_options[] = {
428
{ "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
429
{ "-delay", ".delay", XrmoptionSepArg, 0 },
430
{ "-colorscheme", ".colorscheme", XrmoptionSepArg, 0 },
431
{ "-restart", ".restart", XrmoptionSepArg, 0 },
432
{ "-batchcount", ".batchcount", XrmoptionSepArg, 0 },
433
{ "-trail", ".trail", XrmoptionSepArg, 0 },
434
{ 0, 0, 0, 0 } /* end */
438
/* Default xrm resources. */
439
static const char *critical_defaults[] = {
440
".background: black",
441
"*colorscheme: smooth",
451
XSCREENSAVER_MODULE ("Critical", critical)