2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: life.c /main/3 1995/11/02 16:07:44 rswiston $ */
25 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
26 * (c) Copyright 1993, 1994 International Business Machines Corp. *
27 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
28 * (c) Copyright 1993, 1994 Novell, Inc. *
31 * life.c - Conway's game of Life for dtscreen, the X Window System lockscreen.
33 * Copyright (c) 1991 by Patrick J. Naughton.
35 * See dtscreen.c for copying information.
38 * 24-May-91: Added wraparound code from johnson@bugs.comm.mot.com.
39 * Made old cells stay blue.
40 * Made batchcount control the number of generations till restart.
41 * 29-Jul-90: support for multiple screens.
42 * 07-Feb-90: remove bogus semi-colon after #include line.
43 * 15-Dec-89: Fix for proper skipping of {White,Black}Pixel() in colors.
44 * 08-Oct-89: Moved seconds() to an extern.
45 * 20-Sep-89: Written (life algorithm courtesy of Jim Graham, flar@sun.com).
49 #include "lifeicon.bit"
51 static XImage logo = {
52 0, 0, /* width, height */
53 0, XYBitmap, 0, /* xoffset, format, data */
54 LSBFirst, 8, /* byte-order, bitmap-unit */
55 LSBFirst, 8, 1 /* bitmap-bit-order, bitmap-pad, depth */
57 #define min(a, b) ((a)<(b)?(a):(b))
74 unsigned char buffer[(MAXROWS + 2) * (MAXCOLS + 2) + 2];
75 unsigned char tempbuf[MAXCOLS * 2];
76 unsigned char lastbuf[MAXCOLS];
77 unsigned char agebuf[(MAXROWS + 2) * (MAXCOLS + 2)];
80 static int icon_width, icon_height;
82 /* Buffer stores the data for each cell. Each cell is stored as
83 * 8 bits representing the presence of a critter in each of it's
84 * surrounding 8 cells. There is an empty row and column around
85 * the whole array to allow stores without bounds checking as well
86 * as an extra row at the end for the fetches into tempbuf.
88 * Tempbuf stores the data for the next two rows so that we know
89 * the state of those critter before he was modified by the fate
90 * of the critters that have already been processed.
92 * Agebuf stores the age of each critter.
104 /* Fates is a lookup table for the fate of a critter. The 256
105 * entries represent the 256 possible combinations of the 8
106 * neighbor cells. Each entry is one of BIRTH (create a cell
107 * or leave one alive), SAME (leave the cell alive or dead),
108 * or DEATH (kill anything in the cell).
113 static unsigned char fates[256];
114 static int initialized = 0;
116 const int patterns[][128] = {
118 -3, -3, -2, -3, -1, -3,
119 -3, -2, -2, -2, -1, -2,
120 -3, -1, -2, -1, -1, -1,
127 1, 1, 2, 1, 3, 1, 4, 1, 5, 1,
145 -7, -3, -6, -3, -2, -3, -1, -3, 0, -3, 1, -3, 5, -3, 6, -3,
146 -7, -2, -5, -2, -3, -2, 2, -2, 4, -2, 6, -2,
147 -5, -1, -3, -1, -2, -1, 2, -1, 4, -1,
148 -7, 0, -5, 0, -3, 0, 2, 0, 4, 0, 6, 0,
149 -7, 1, -6, 1, -2, 1, -1, 1, 0, 1, 1, 1, 5, 1, 6, 1,
155 -6, -6, -5, -6, 6, -6, 7, -6,
156 -6, -5, -5, -5, 6, -5, 7, -5,
158 -7, 6, -5, 6, 6, 6, 8, 6,
159 -7, 7, -5, 7, 6, 7, 8, 7,
160 -7, 8, -6, 8, 7, 8, 8, 8,
167 -7, -5, -3, -5, -2, -5,
185 -8, -7, -7, -7, -5, -7,
186 -8, -6, -7, -6, -4, -6, -1, -6,
196 -4, -5, -3, -5, -2, -5, -1, -5,
197 -5, -4, -3, -4, 0, -4, 2, -4, 3, -4,
198 -5, -3, -1, -3, 0, -3, 2, -3, 3, -3,
199 -8, -2, -7, -2, -5, -2, -2, -2, 0, -2,
200 -8, -1, -7, -1, -5, -1, 0, -1,
201 -4, 0, -3, 0, -2, 0, -1, 0,
207 -1, -1, 0, -1, 1, -1,
213 -3, -1, -2, -1, -1, -1, 1, -1, 2, -1, 3, -1,
214 -3, 0, -2, 0, 1, 0, 2, 0,
215 -3, 1, -2, 1, -1, 1, 1, 1, 2, 1, 3, 1,
219 -3, -1, -2, -1, -1, -1, 1, -1, 2, -1, 3, -1,
220 -3, 0, -2, 0, 2, 0, 3, 0,
221 -3, 1, -2, 1, -1, 1, 1, 1, 2, 1, 3, 1,
225 -15, 0, -14, 0, -13, 0, -12, 0, -11, 0,
226 -10, 0, -9, 0, -8, 0, -7, 0, -6, 0,
227 -5, 0, -4, 0, -3, 0, -2, 0, -1, 0,
228 4, 0, 3, 0, 2, 0, 1, 0, 0, 0,
229 9, 0, 8, 0, 7, 0, 6, 0, 5, 0,
230 14, 0, 13, 0, 12, 0, 11, 0, 10, 0,
234 -7, -2, -6, -2, -5, -2, -4, -2, -3, -2,
235 -2, -2, -1, -2, 0, -2, 1, -2, 2, -2,
236 -5, -1, -4, -1, -3, -1, -2, -1, -1, -1,
237 0, -1, 1, -1, 2, -1, 3, -1, 4, -1,
238 -3, 0, -2, 0, -1, 0, 0, 0, 1, 0,
239 2, 0, 3, 0, 4, 0, 5, 0, 6, 0,
240 -10, 1, -9, 1, -8, 1, -7, 1, -6, 1,
241 -5, 1, -4, 1, -3, 1, -2, 1, -1, 1,
242 -10, 2, -9, 2, -8, 2, -7, 2, -6, 2,
243 -5, 2, -4, 2, -3, 2, -2, 2, -1, 2,
265 -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 4, 0, 3, 0, 2, 0, 1, 0, 0, 0,
306 -4, -4, -3, -4, -2, -4, -1, -4, 0, -4, 1, -4, 2, -4, 3, -4, 4, -4,
307 -4, -3, 0, -3, 4, -3,
308 -4, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -2, 4, -2,
309 -4, -1, -2, -1, 2, -1, 4, -1,
310 -4, 0, -2, 0, -1, 0, 0, 0, 1, 0, 2, 0, 4, 0,
311 -4, 1, -2, 1, 2, 1, 4, 1,
312 -4, 2, -2, 2, -1, 2, 0, 2, 1, 2, 2, 2, 4, 2,
314 -4, 4, -3, 4, -2, 4, -1, 4, 0, 4, 1, 4, 2, 4, 3, 4, 4, 4,
319 #define NPATS (sizeof patterns / sizeof patterns[0])
323 drawcell(pwin, row, col)
329 lp = (lifestruct *)pwin->data;
330 XSetForeground(dsp, pwin->gc, WhitePixelOfScreen(pwin->perscreen->screen));
331 if (!mono && pwin->perscreen->npixels > 2) {
332 unsigned char *loc = lp->buffer + ((row + 1) * (lp->ncols + 2)) + col + 1;
333 unsigned char *ageptr = lp->agebuf + (loc - lp->buffer);
334 unsigned char age = *ageptr;
336 /* if we aren't up to blue yet, then keep aging the cell. */
337 if (age < (unsigned char) (pwin->perscreen->npixels * 0.7))
340 XSetForeground(dsp, pwin->gc, pwin->perscreen->pixels[age]);
344 XFillRectangle(dsp, pwin->w, pwin->gc,
345 lp->xb + lp->xs * col, lp->yb + lp->ys * row, lp->xs, lp->ys);
347 XPutImage(dsp, pwin->w, pwin->gc, &logo,
348 0, 0, lp->xb + lp->xs * col, lp->yb + lp->ys * row,
349 icon_width, icon_height);
354 erasecell(pwin, row, col)
358 lifestruct *lp = (lifestruct *)pwin->data;
359 XSetForeground(dsp, pwin->gc, BlackPixelOfScreen(pwin->perscreen->screen));
360 XFillRectangle(dsp, pwin->w, pwin->gc,
361 lp->xb + lp->xs * col, lp->yb + lp->ys * row, lp->xs, lp->ys);
370 lifestruct *lp = (lifestruct *)pwin->data;
371 unsigned char *ulloc, *ucloc, *urloc, *clloc, *crloc, *llloc, *lcloc, *lrloc,
373 int off, row, col, lastrow;
375 lastrow = (lp->nrows) * (lp->ncols + 2);
376 off = loc - lp->buffer;
377 col = off % (lp->ncols + 2);
378 row = (off - col) / (lp->ncols + 2);
379 ulloc = loc - lp->ncols - 3;
380 ucloc = loc - lp->ncols - 2;
381 urloc = loc - lp->ncols - 1;
385 llloc = loc + lp->ncols + 1;
386 lcloc = loc + lp->ncols + 2;
387 lrloc = loc + lp->ncols + 3;
393 if (row == lp->nrows) {
403 if (col == lp->ncols) {
418 *(lp->agebuf + (loc - lp->buffer)) = 0;
427 lifestruct *lp = (lifestruct *)pwin->data;
429 unsigned char *ulloc, *ucloc, *urloc, *clloc, *crloc, *llloc, *lcloc,
431 int off, row, col, lastrow;
433 lastrow = (lp->nrows) * (lp->ncols + 2);
434 off = loc - lp->buffer;
435 row = off / (lp->ncols + 2);
436 col = off % (lp->ncols + 2);
437 row = (off - col) / (lp->ncols + 2);
438 ulloc = loc - lp->ncols - 3;
439 ucloc = loc - lp->ncols - 2;
440 urloc = loc - lp->ncols - 1;
444 llloc = loc + lp->ncols + 1;
445 lcloc = loc + lp->ncols + 2;
446 lrloc = loc + lp->ncols + 3;
452 if (row == lp->nrows) {
462 if (col == lp->ncols) {
480 setcell(pwin, row, col)
485 lifestruct *lp = (lifestruct *)pwin->data;
488 loc = lp->buffer + ((row + 1) * (lp->ncols + 2)) + col + 1;
490 drawcell(pwin, row, col);
497 int i, bits, neighbors;
499 for (i = 0; i < 256; i++) {
501 for (bits = i; bits; bits &= (bits - 1))
505 else if (neighbors == 2)
519 XWindowAttributes xgwa;
522 if (pwin->data) free(pwin->data);
523 pwin->data = (void *)malloc(sizeof(lifestruct));
524 memset(pwin->data, '\0', sizeof(lifestruct));
525 lp = (lifestruct *)pwin->data;
527 lp->shooterTime = seconds();
528 icon_width = lifeicon_width;
529 icon_height = lifeicon_height;
534 logo.data = (char *) lifeicon_bits;
535 logo.width = icon_width;
536 logo.height = icon_height;
537 logo.bytes_per_line = (icon_width + 7) / 8;
539 XGetWindowAttributes(dsp, pwin->w, &xgwa);
540 lp->width = xgwa.width;
541 lp->height = xgwa.height;
542 lp->pixelmode = (lp->width < 4 * icon_width);
547 lp->ncols = min(lp->width / icon_width, MAXCOLS);
548 lp->nrows = min(lp->height / icon_height, MAXROWS);
550 /* For the dtstyle preview screen, the rows and columns can
551 * be less than 32 regardless of the pixelmode calculation.
552 * This can cause the row/column calculations below to go
553 * negative, which causes very bad things to happen. Until we
554 * get an official fix, this will keep life from core dumping.
556 if ((lp->ncols < 32) || (lp->nrows < 32)) {
561 lp->xs = lp->width / lp->ncols;
562 lp->ys = lp->height / lp->nrows;
563 lp->xb = (lp->width - lp->xs * lp->ncols) / 2;
564 lp->yb = (lp->height - lp->ys * lp->nrows) / 2;
566 XSetForeground(dsp, pwin->gc, BlackPixelOfScreen(pwin->perscreen->screen));
567 XFillRectangle(dsp, pwin->w, pwin->gc, 0, 0, lp->width, lp->height);
569 memset(lp->buffer, '\0', sizeof(lp->buffer));
570 patptr = (int *)&patterns[random() % NPATS][0];
571 while ((col = *patptr++) != 99) {
573 col += lp->ncols / 2;
574 row += lp->nrows / 2;
575 if ((row >= 0) && (row < lp->nrows) && (col >= 0) && (col < lp->ncols))
576 setcell(pwin, row, col);
585 unsigned char *loc, *temploc, *lastloc;
588 lifestruct *lp = (lifestruct *)pwin->data;
590 loc = lp->buffer + lp->ncols + 2 + 1;
591 temploc = lp->tempbuf;
592 /* copy the first 2 rows to the tempbuf */
593 memcpy(temploc, loc, lp->ncols);
594 memcpy(temploc + lp->ncols, loc + lp->ncols + 2, lp->ncols);
596 lastloc = lp->lastbuf;
597 /* copy the last row to another buffer for wraparound */
598 memcpy(lastloc, loc + ((lp->nrows - 1) * (lp->ncols + 2)), lp->ncols);
600 for (row = 0; row < lp->nrows; ++row) {
601 for (col = 0; col < lp->ncols; ++col) {
602 fate = fates[*temploc];
603 *temploc = (row == (lp->nrows - 3)) ?
605 *(loc + (lp->ncols + 2) * 2);
608 if (!(*(loc + 1) & RT)) {
613 if (*(loc + 1) & RT) {
614 drawcell(pwin, row, col);
618 if (*(loc + 1) & RT) {
619 life_kill(pwin, loc);
620 erasecell(pwin, row, col);
628 if (temploc >= lp->tempbuf + lp->ncols * 2)
629 temploc = lp->tempbuf;
632 if (++lp->generation > batchcount)
636 * generate a randomized shooter aimed roughly toward the center of the
637 * screen after timeout.
640 if (seconds() - lp->shooterTime > TIMEOUT) {
641 int hsp = random() % (lp->ncols - 5) + 3;
642 int vsp = random() % (lp->nrows - 5) + 3;
645 if (vsp > lp->nrows / 2)
647 if (hsp > lp->ncols / 2)
649 setcell(pwin, vsp + 0 * voff, hsp + 2 * hoff);
650 setcell(pwin, vsp + 1 * voff, hsp + 2 * hoff);
651 setcell(pwin, vsp + 2 * voff, hsp + 2 * hoff);
652 setcell(pwin, vsp + 2 * voff, hsp + 1 * hoff);
653 setcell(pwin, vsp + 1 * voff, hsp + 0 * hoff);
654 lp->shooterTime = seconds();