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"
52 static XImage logo = {
53 0, 0, /* width, height */
54 0, XYBitmap, 0, /* xoffset, format, data */
55 LSBFirst, 8, /* byte-order, bitmap-unit */
56 LSBFirst, 8, 1 /* bitmap-bit-order, bitmap-pad, depth */
58 #define min(a, b) ((a)<(b)?(a):(b))
75 unsigned char buffer[(MAXROWS + 2) * (MAXCOLS + 2) + 2];
76 unsigned char tempbuf[MAXCOLS * 2];
77 unsigned char lastbuf[MAXCOLS];
78 unsigned char agebuf[(MAXROWS + 2) * (MAXCOLS + 2)];
81 static int icon_width, icon_height;
83 /* Buffer stores the data for each cell. Each cell is stored as
84 * 8 bits representing the presence of a critter in each of it's
85 * surrounding 8 cells. There is an empty row and column around
86 * the whole array to allow stores without bounds checking as well
87 * as an extra row at the end for the fetches into tempbuf.
89 * Tempbuf stores the data for the next two rows so that we know
90 * the state of those critter before he was modified by the fate
91 * of the critters that have already been processed.
93 * Agebuf stores the age of each critter.
105 /* Fates is a lookup table for the fate of a critter. The 256
106 * entries represent the 256 possible combinations of the 8
107 * neighbor cells. Each entry is one of BIRTH (create a cell
108 * or leave one alive), SAME (leave the cell alive or dead),
109 * or DEATH (kill anything in the cell).
114 static unsigned char fates[256];
115 static int initialized = 0;
117 const int patterns[][128] = {
119 -3, -3, -2, -3, -1, -3,
120 -3, -2, -2, -2, -1, -2,
121 -3, -1, -2, -1, -1, -1,
128 1, 1, 2, 1, 3, 1, 4, 1, 5, 1,
146 -7, -3, -6, -3, -2, -3, -1, -3, 0, -3, 1, -3, 5, -3, 6, -3,
147 -7, -2, -5, -2, -3, -2, 2, -2, 4, -2, 6, -2,
148 -5, -1, -3, -1, -2, -1, 2, -1, 4, -1,
149 -7, 0, -5, 0, -3, 0, 2, 0, 4, 0, 6, 0,
150 -7, 1, -6, 1, -2, 1, -1, 1, 0, 1, 1, 1, 5, 1, 6, 1,
156 -6, -6, -5, -6, 6, -6, 7, -6,
157 -6, -5, -5, -5, 6, -5, 7, -5,
159 -7, 6, -5, 6, 6, 6, 8, 6,
160 -7, 7, -5, 7, 6, 7, 8, 7,
161 -7, 8, -6, 8, 7, 8, 8, 8,
168 -7, -5, -3, -5, -2, -5,
186 -8, -7, -7, -7, -5, -7,
187 -8, -6, -7, -6, -4, -6, -1, -6,
197 -4, -5, -3, -5, -2, -5, -1, -5,
198 -5, -4, -3, -4, 0, -4, 2, -4, 3, -4,
199 -5, -3, -1, -3, 0, -3, 2, -3, 3, -3,
200 -8, -2, -7, -2, -5, -2, -2, -2, 0, -2,
201 -8, -1, -7, -1, -5, -1, 0, -1,
202 -4, 0, -3, 0, -2, 0, -1, 0,
208 -1, -1, 0, -1, 1, -1,
214 -3, -1, -2, -1, -1, -1, 1, -1, 2, -1, 3, -1,
215 -3, 0, -2, 0, 1, 0, 2, 0,
216 -3, 1, -2, 1, -1, 1, 1, 1, 2, 1, 3, 1,
220 -3, -1, -2, -1, -1, -1, 1, -1, 2, -1, 3, -1,
221 -3, 0, -2, 0, 2, 0, 3, 0,
222 -3, 1, -2, 1, -1, 1, 1, 1, 2, 1, 3, 1,
226 -15, 0, -14, 0, -13, 0, -12, 0, -11, 0,
227 -10, 0, -9, 0, -8, 0, -7, 0, -6, 0,
228 -5, 0, -4, 0, -3, 0, -2, 0, -1, 0,
229 4, 0, 3, 0, 2, 0, 1, 0, 0, 0,
230 9, 0, 8, 0, 7, 0, 6, 0, 5, 0,
231 14, 0, 13, 0, 12, 0, 11, 0, 10, 0,
235 -7, -2, -6, -2, -5, -2, -4, -2, -3, -2,
236 -2, -2, -1, -2, 0, -2, 1, -2, 2, -2,
237 -5, -1, -4, -1, -3, -1, -2, -1, -1, -1,
238 0, -1, 1, -1, 2, -1, 3, -1, 4, -1,
239 -3, 0, -2, 0, -1, 0, 0, 0, 1, 0,
240 2, 0, 3, 0, 4, 0, 5, 0, 6, 0,
241 -10, 1, -9, 1, -8, 1, -7, 1, -6, 1,
242 -5, 1, -4, 1, -3, 1, -2, 1, -1, 1,
243 -10, 2, -9, 2, -8, 2, -7, 2, -6, 2,
244 -5, 2, -4, 2, -3, 2, -2, 2, -1, 2,
266 -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 4, 0, 3, 0, 2, 0, 1, 0, 0, 0,
307 -4, -4, -3, -4, -2, -4, -1, -4, 0, -4, 1, -4, 2, -4, 3, -4, 4, -4,
308 -4, -3, 0, -3, 4, -3,
309 -4, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -2, 4, -2,
310 -4, -1, -2, -1, 2, -1, 4, -1,
311 -4, 0, -2, 0, -1, 0, 0, 0, 1, 0, 2, 0, 4, 0,
312 -4, 1, -2, 1, 2, 1, 4, 1,
313 -4, 2, -2, 2, -1, 2, 0, 2, 1, 2, 2, 2, 4, 2,
315 -4, 4, -3, 4, -2, 4, -1, 4, 0, 4, 1, 4, 2, 4, 3, 4, 4, 4,
320 #define NPATS (sizeof patterns / sizeof patterns[0])
324 drawcell(pwin, row, col)
330 lp = (lifestruct *)pwin->data;
331 XSetForeground(dsp, pwin->gc, WhitePixelOfScreen(pwin->perscreen->screen));
332 if (!mono && pwin->perscreen->npixels > 2) {
333 unsigned char *loc = lp->buffer + ((row + 1) * (lp->ncols + 2)) + col + 1;
334 unsigned char *ageptr = lp->agebuf + (loc - lp->buffer);
335 unsigned char age = *ageptr;
337 /* if we aren't up to blue yet, then keep aging the cell. */
338 if (age < (unsigned char) (pwin->perscreen->npixels * 0.7))
341 XSetForeground(dsp, pwin->gc, pwin->perscreen->pixels[age]);
345 XFillRectangle(dsp, pwin->w, pwin->gc,
346 lp->xb + lp->xs * col, lp->yb + lp->ys * row, lp->xs, lp->ys);
348 XPutImage(dsp, pwin->w, pwin->gc, &logo,
349 0, 0, lp->xb + lp->xs * col, lp->yb + lp->ys * row,
350 icon_width, icon_height);
355 erasecell(pwin, row, col)
359 lifestruct *lp = (lifestruct *)pwin->data;
360 XSetForeground(dsp, pwin->gc, BlackPixelOfScreen(pwin->perscreen->screen));
361 XFillRectangle(dsp, pwin->w, pwin->gc,
362 lp->xb + lp->xs * col, lp->yb + lp->ys * row, lp->xs, lp->ys);
371 lifestruct *lp = (lifestruct *)pwin->data;
372 unsigned char *ulloc, *ucloc, *urloc, *clloc, *crloc, *llloc, *lcloc, *lrloc,
374 int off, row, col, lastrow;
376 lastrow = (lp->nrows) * (lp->ncols + 2);
377 off = loc - lp->buffer;
378 col = off % (lp->ncols + 2);
379 row = (off - col) / (lp->ncols + 2);
380 ulloc = loc - lp->ncols - 3;
381 ucloc = loc - lp->ncols - 2;
382 urloc = loc - lp->ncols - 1;
386 llloc = loc + lp->ncols + 1;
387 lcloc = loc + lp->ncols + 2;
388 lrloc = loc + lp->ncols + 3;
394 if (row == lp->nrows) {
404 if (col == lp->ncols) {
419 *(lp->agebuf + (loc - lp->buffer)) = 0;
428 lifestruct *lp = (lifestruct *)pwin->data;
430 unsigned char *ulloc, *ucloc, *urloc, *clloc, *crloc, *llloc, *lcloc,
432 int off, row, col, lastrow;
434 lastrow = (lp->nrows) * (lp->ncols + 2);
435 off = loc - lp->buffer;
436 row = off / (lp->ncols + 2);
437 col = off % (lp->ncols + 2);
438 row = (off - col) / (lp->ncols + 2);
439 ulloc = loc - lp->ncols - 3;
440 ucloc = loc - lp->ncols - 2;
441 urloc = loc - lp->ncols - 1;
445 llloc = loc + lp->ncols + 1;
446 lcloc = loc + lp->ncols + 2;
447 lrloc = loc + lp->ncols + 3;
453 if (row == lp->nrows) {
463 if (col == lp->ncols) {
481 setcell(pwin, row, col)
486 lifestruct *lp = (lifestruct *)pwin->data;
489 loc = lp->buffer + ((row + 1) * (lp->ncols + 2)) + col + 1;
491 drawcell(pwin, row, col);
498 int i, bits, neighbors;
500 for (i = 0; i < 256; i++) {
502 for (bits = i; bits; bits &= (bits - 1))
506 else if (neighbors == 2)
520 XWindowAttributes xgwa;
523 if (pwin->data) free(pwin->data);
524 pwin->data = (void *)malloc(sizeof(lifestruct));
525 memset(pwin->data, '\0', sizeof(lifestruct));
526 lp = (lifestruct *)pwin->data;
528 lp->shooterTime = seconds();
529 icon_width = lifeicon_width;
530 icon_height = lifeicon_height;
535 logo.data = (char *) lifeicon_bits;
536 logo.width = icon_width;
537 logo.height = icon_height;
538 logo.bytes_per_line = (icon_width + 7) / 8;
540 XGetWindowAttributes(dsp, pwin->w, &xgwa);
541 lp->width = xgwa.width;
542 lp->height = xgwa.height;
543 lp->pixelmode = (lp->width < 4 * icon_width);
548 lp->ncols = min(lp->width / icon_width, MAXCOLS);
549 lp->nrows = min(lp->height / icon_height, MAXROWS);
551 /* For the dtstyle preview screen, the rows and columns can
552 * be less than 32 regardless of the pixelmode calculation.
553 * This can cause the row/column calculations below to go
554 * negative, which causes very bad things to happen. Until we
555 * get an official fix, this will keep life from core dumping.
557 if ((lp->ncols < 32) || (lp->nrows < 32)) {
562 lp->xs = lp->width / lp->ncols;
563 lp->ys = lp->height / lp->nrows;
564 lp->xb = (lp->width - lp->xs * lp->ncols) / 2;
565 lp->yb = (lp->height - lp->ys * lp->nrows) / 2;
567 XSetForeground(dsp, pwin->gc, BlackPixelOfScreen(pwin->perscreen->screen));
568 XFillRectangle(dsp, pwin->w, pwin->gc, 0, 0, lp->width, lp->height);
570 memset(lp->buffer, '\0', sizeof(lp->buffer));
571 patptr = (int *)&patterns[random() % NPATS][0];
572 while ((col = *patptr++) != 99) {
574 col += lp->ncols / 2;
575 row += lp->nrows / 2;
576 if ((row >= 0) && (row < lp->nrows) && (col >= 0) && (col < lp->ncols))
577 setcell(pwin, row, col);
586 unsigned char *loc, *temploc, *lastloc;
589 lifestruct *lp = (lifestruct *)pwin->data;
591 loc = lp->buffer + lp->ncols + 2 + 1;
592 temploc = lp->tempbuf;
593 /* copy the first 2 rows to the tempbuf */
594 memcpy(temploc, loc, lp->ncols);
595 memcpy(temploc + lp->ncols, loc + lp->ncols + 2, lp->ncols);
597 lastloc = lp->lastbuf;
598 /* copy the last row to another buffer for wraparound */
599 memcpy(lastloc, loc + ((lp->nrows - 1) * (lp->ncols + 2)), lp->ncols);
601 for (row = 0; row < lp->nrows; ++row) {
602 for (col = 0; col < lp->ncols; ++col) {
603 fate = fates[*temploc];
604 *temploc = (row == (lp->nrows - 3)) ?
606 *(loc + (lp->ncols + 2) * 2);
609 if (!(*(loc + 1) & RT)) {
614 if (*(loc + 1) & RT) {
615 drawcell(pwin, row, col);
619 if (*(loc + 1) & RT) {
620 life_kill(pwin, loc);
621 erasecell(pwin, row, col);
629 if (temploc >= lp->tempbuf + lp->ncols * 2)
630 temploc = lp->tempbuf;
633 if (++lp->generation > batchcount)
637 * generate a randomized shooter aimed roughly toward the center of the
638 * screen after timeout.
641 if (seconds() - lp->shooterTime > TIMEOUT) {
642 int hsp = random() % (lp->ncols - 5) + 3;
643 int vsp = random() % (lp->nrows - 5) + 3;
646 if (vsp > lp->nrows / 2)
648 if (hsp > lp->ncols / 2)
650 setcell(pwin, vsp + 0 * voff, hsp + 2 * hoff);
651 setcell(pwin, vsp + 1 * voff, hsp + 2 * hoff);
652 setcell(pwin, vsp + 2 * voff, hsp + 2 * hoff);
653 setcell(pwin, vsp + 2 * voff, hsp + 1 * hoff);
654 setcell(pwin, vsp + 1 * voff, hsp + 0 * hoff);
655 lp->shooterTime = seconds();