1 /*
2 * XLife Copyright 1989 Jon Bennett jb7m+@andrew.cmu.edu, jcrb@cs.cmu.edu
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. The copyright holders make no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 *
22 * CMU SUCKS
23 */
24
25 /*
26 * A lot of modifications were added at 2001, 2011-14 by Vladimir Lidovski vol.litwr@gmail.com
27 * (C) This version of XLife may be used under the same conditions as mentioned above
28 * $Id: main.c 279 2014-01-14 08:09:57Z litwr $
29 */
30
31 #include <X11/Xlib.h>
32 #include <X11/Xutil.h>
33 #include <X11/Xos.h>
34 #include <X11/Xatom.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include "defs.h"
38 #include "tile.h"
39 #include "file.h"
40 #include "xwidget.h"
41 #include "colors.h"
42 #include "clipboard.h"
43 #include "patchlevel.h"
44 #include "framebuffer.h"
45 #include "history.h"
46 #include "topology.h"
47
48 /*#define char unsigned char*/
49 #include "icon.h"
50 #include "cursor.h"
51 /*#undef char*/
52
53 #ifndef GRAB_FRACTION
54 #define GRAB_FRACTION 0.8 /* fraction of screen to size */
55 #endif /* GRAB_FRACTION */
56
57 coord_t savex, savey; /* last point seen during boxing */
58 static coord_t xmarker[3], ymarker[3], linex, liney;
59
redraw_lifew()60 void redraw_lifew() {
61 XClearWindow(disp, lifew);
62 pivot = 0;
63 fb_clear();
64 drawboundedgrid();
65 redisplay(MESH);
66 }
67
DoExpose(Window win)68 void DoExpose(Window win) {
69 if (convmode) return;
70 if (win == lifew) {
71 XClearWindow(disp, lifew);
72 pivot = 0;
73 drawboundedgrid();
74 #if VFREQ != 0
75 prev_vsync.tv_sec--;
76 #endif
77 redisplay(MESH + EXPOSE);
78 }
79 else if (win == inputw) {
80 XClearWindow(disp, inputw);
81 XDrawString(disp, inputw, ntextgc, INPUTXOFF, INPUTYOFF, inpbuf,
82 strlen(inpbuf));
83 }
84 else if (win == rulew)
85 showrules();
86 else if (win == statew)
87 showstates();
88 else if (win == loadw)
89 drawloadwidget();
90 else if (win == helpw) {
91 if (helpw_mode == -3)
92 redraw_slashinfo();
93 else if (helpw_mode == -1)
94 redraw_help();
95 else if (helpw_mode < 0)
96 redraw_viewvars();
97 else
98 eo_comments = redraw_comments();
99 }
100 }
101
ResizeLW(int oheight)102 void ResizeLW(int oheight) {
103 XResizeWindow(disp, rulew, rulew_len, INPUTH);
104 XMoveWindow(disp, rulew, width - rulew_len
105 - dispcoord*(COORDW + BORDERWIDTH) - BORDERWIDTH, oheight);
106 if (maxstates > 2) {
107 if (width > maxstates*(FONTWIDTH + 3) - BORDERWIDTH - STATEOFF) {
108 statescols = maxstates;
109 XMoveWindow(disp, statew, width - maxstates*(FONTWIDTH + 3)
110 - 3*BORDERWIDTH - STATEOFF, BORDERWIDTH);
111 XResizeWindow(disp, statew, maxstates*(FONTWIDTH + 3) + STATEOFF,
112 INPUTH);
113 }
114 else {
115 int w, h;
116 w = (width + BORDERWIDTH)/(FONTWIDTH + 3);
117 h = maxstates/w + (maxstates%w? 1: 0);
118 statescols = maxstates/h + (maxstates%h? 1: 0);
119 XMoveWindow(disp, statew, width - statescols*(FONTWIDTH + 3)
120 - 3*BORDERWIDTH - STATEOFF, BORDERWIDTH);
121 XResizeWindow(disp, statew, statescols*(FONTWIDTH + 3) + STATEOFF,
122 (FONTHEIGHT + 3)*h + STATEOFF);
123 }
124 showstates();
125 }
126 else
127 XLowerWindow(disp, statew);
128 XMoveWindow(disp, coordw, width - dispcoord*(COORDW + BORDERWIDTH)
129 - BORDERWIDTH, oheight);
130 }
131
DoResize(void)132 void DoResize(void) {
133 int owidth = width, oheight = height;
134 if ((width = event.xconfigure.width) < 50)
135 XResizeWindow(disp, mainw, width = 50, height);
136 if ((height = event.xconfigure.height) < 70)
137 XResizeWindow(disp, mainw, width, height = 70);
138 xpos += sgn(owidth - width)*shr(abs(owidth - width), scale + 1);
139 ypos += sgn(oheight - height)*shr(abs(oheight - height), scale + 1);
140 inputlength = width/FONTWIDTH;
141 oheight = height - INPUTH - BORDERWIDTH*3;
142 if (oheight < 5) oheight = 5;
143 ResizeLW(oheight);
144 XResizeWindow(disp, lifew, width - BORDERWIDTH*2, oheight);
145 XResizeWindow(disp, helpw, width - BORDERWIDTH*2, height - BORDERWIDTH*2);
146 if (helpw_mode || eo_comments) DoExpose(helpw);
147 XMoveWindow(disp, inputw, 0, oheight);
148 XResizeWindow(disp, inputw, width - BORDERWIDTH*2, INPUTH);
149 }
150
alloc_states(unsigned new_ev_mode,unsigned newmaxstates)151 void alloc_states(unsigned new_ev_mode, unsigned newmaxstates) {
152 if (maxstates == newmaxstates && new_ev_mode == ev_mode)
153 return;
154 confirmload(); /* it is necessary for changesize */
155 /* if (newmaxstates < maxstates) clear_all();*/
156 clipboard_copy(&active);
157 if (new_ev_mode == VALENCE_DRIVEN)
158 changesize(sizeof(struct twostate_t));
159 else if (new_ev_mode == PAYOFF_DRIVEN || new_ev_mode == TAB8_DRIVEN)
160 changesize(sizeof(struct pstate_t));
161 else
162 changesize(sizeof(struct nstate_t)); /* also gstate_t */
163 ev_mode = new_ev_mode;
164 clipboard_flush(&active, maxstates = newmaxstates);
165 ResizeLW(height - INPUTH - BORDERWIDTH*3);
166 }
167
DoKeySymIn(KeySym keysym)168 int DoKeySymIn(KeySym keysym) {
169 int dx, dy;
170 coord_t sxpos, sypos;
171 switch (keysym) {
172 case XK_4:
173 case XK_KP_4:
174 case XK_Left:
175 case XK_KP_Left:
176 prep_tentative();
177 if (event.xkey.state & ShiftMask)
178 xpos -= dx = SCALE(width/4);
179 else
180 xpos -= dx = (scale >= 0) ? 1 : 1 << -scale;
181 display_move(0, -dx, 0);
182 break;
183 case XK_6:
184 case XK_KP_6:
185 case XK_Right:
186 case XK_KP_Right:
187 prep_tentative();
188 if (event.xkey.state & ShiftMask)
189 xpos += dx = SCALE(width/4);
190 else
191 xpos += dx = (scale >= 0) ? 1 : 1 << -scale;
192 display_move(0, dx, 0);
193 break;
194 case XK_8:
195 case XK_KP_8:
196 case XK_Up:
197 case XK_KP_Up:
198 prep_tentative();
199 if (event.xkey.state & ShiftMask)
200 ypos -= dy = SCALE(height/4);
201 else
202 ypos -= dy = (scale >= 0) ? 1 : 1 << -scale;
203 display_move(0, 0, -dy);
204 break;
205 case XK_2:
206 case XK_KP_2:
207 case XK_Down:
208 case XK_KP_Down:
209 prep_tentative();
210 if (event.xkey.state & ShiftMask)
211 ypos += dy = SCALE(height/4);
212 else
213 ypos += dy = (scale >= 0) ? 1 : 1 << -scale;
214 display_move(0, 0, dy);
215 break;
216 case XK_Home:
217 case XK_7:
218 case XK_KP_7:
219 case XK_KP_Home:
220 prep_tentative();
221 if (event.xkey.state & ShiftMask) {
222 xpos -= dx = SCALE(width/4);
223 ypos -= dy = SCALE(height/4);
224 }
225 else {
226 xpos -= dx = (scale >= 0) ? 1 : 1 << -scale;
227 ypos -= dy = (scale >= 0) ? 1 : 1 << -scale;
228 }
229 display_move(0, -dx, -dy);
230 break;
231 case XK_Page_Up:
232 case XK_9:
233 case XK_KP_9:
234 case XK_KP_Page_Up:
235 prep_tentative();
236 if (event.xkey.state & ShiftMask) {
237 xpos += dx = SCALE(width/4);
238 ypos -= dy = SCALE(height/4);
239 }
240 else {
241 xpos += dx = (scale >= 0) ? 1 : 1 << -scale;
242 ypos -= dy = (scale >= 0) ? 1 : 1 << -scale;
243 }
244 display_move(0, dx, -dy);
245 break;
246 case XK_Page_Down:
247 case XK_3:
248 case XK_KP_3:
249 case XK_KP_Page_Down:
250 prep_tentative();
251 if (event.xkey.state & ShiftMask) {
252 xpos += dx = SCALE(width/4);
253 ypos += dy = SCALE(height/4);
254 }
255 else {
256 xpos += dx = (scale >= 0) ? 1 : 1 << -scale;
257 ypos += dy = (scale >= 0) ? 1 : 1 << -scale;
258 }
259 display_move(0, dx, dy);
260 break;
261 case XK_End:
262 case XK_1:
263 case XK_KP_1:
264 case XK_KP_End:
265 prep_tentative();
266 if (event.xkey.state & ShiftMask) {
267 xpos -= dx = SCALE(width/4),
268 ypos += dy = SCALE(height/4);
269 }
270 else {
271 xpos -= dx = (scale >= 0) ? 1 : 1 << -scale;
272 ypos += dy = (scale >= 0) ? 1 : 1 << -scale;
273 }
274 display_move(0, -dx, dy);
275 break;
276 case XK_5:
277 case XK_KP_5:
278 case XK_KP_Begin:
279 prep_tentative();
280 sxpos = xpos, sypos = ypos;
281 center();
282 display_move(0, xpos - sxpos, ypos - sypos);
283 break;
284 case XK_0:
285 case XK_KP_0:
286 case XK_KP_Insert:
287 prep_tentative();
288 sxpos = xpos, sypos = ypos;
289 median();
290 display_move(0, xpos - sxpos, ypos - sypos);
291 break;
292 case XK_Help:
293 help();
294 break;
295 case XK_Tab:
296 if (tentative.tiles && paintcolor > 1)
297 change_tentative_color();
298 break;
299 default:
300 return 0;
301 }
302 /* could process it */
303 return 1;
304 }
305
inc_scale(void)306 void inc_scale(void) {
307 if (scale < MAXSCALE) {
308 setscale(++scale);
309 xpos += SCALE(event.xmotion.x);
310 ypos += SCALE(event.xmotion.y);
311 redraw_lifew();
312 }
313 }
314
dec_scale(void)315 void dec_scale(void) {
316 if (scale > MINSCALE) {
317 xpos -= SCALE(event.xmotion.x);
318 ypos -= SCALE(event.xmotion.y);
319 setscale(--scale);
320 redraw_lifew();
321 }
322 }
323
set_active_rules(char * s,int force)324 void set_active_rules(char *s, int force) {
325 int i = rulew_len;
326 strcpy(active_rules, s);
327 rulew_len = (strlen(s) + 1)*FONTWIDTH;
328 if (force && i != rulew_len)
329 ResizeLW(height - INPUTH - BORDERWIDTH*3);
330 }
331
rules_changed(void)332 int rules_changed(void) {
333 char *pn = active_rules, *po = saved_rules;
334 if (!strcmp(pn, po))
335 return 0;
336 if (strstr(pn, po));
337 else if (strstr(po, pn)) {
338 po = active_rules;
339 pn = saved_rules;
340 }
341 else
342 return 1;
343 if (!strcmp(pn + strlen(po), "+"))
344 return 0;
345 return 1;
346 }
347
fixpatterntopology(void)348 void fixpatterntopology(void) {
349 if (bounding_box(&active) && limits && (active.xmin < x_min_limit && x_min_limit
350 || active.xmax >= x_max_limit && x_max_limit
351 || active.ymin < y_min_limit && y_min_limit
352 || active.ymax >= y_max_limit && y_max_limit)) {
353 make_tentative(active.xmin, active.ymin, active.xmax, active.ymax);
354 copy_tentative();
355 clear_pattern(&tentative);
356 }
357 }
358
fix_mouse_coord(int coord,int limit)359 static int fix_mouse_coord(int coord, int limit) {
360 if (coord < 0)
361 return 0;
362 if (coord > limit)
363 return limit - 40;
364 return coord;
365 }
366
adjust_pivotpos()367 static void adjust_pivotpos() {
368 if (tentative.tiles && bounding_box(&tentative) < 1000000) {
369 /* don't change pivot position for the very big pattern */
370 clipboard_copy(&tentative);
371 clipboard.x -= tentative.xmin - STARTX;
372 clipboard.y -= tentative.ymin - STARTY;
373 if (!wireframe) boxpattern(0);
374 clear_pattern(&tentative);
375 clipboard_flush(&tentative, maxstates);
376 if (!wireframe) boxpattern(CYAN_EVER);
377 }
378 }
379
DoKeyIn(char * kbuf)380 void DoKeyIn(char *kbuf) {
381 int num, dx, dy;
382 switch(kbuf[0]) {
383 case 0:
384 return;
385
386 case 'r':
387 redraw_lifew();
388 displaystats();
389 break;
390
391 case 'R':
392 strcpy(saved_rules, active_rules);
393 newrules();
394 displaystats();
395 if (rules_changed())
396 free_loadscript();
397 showrules();
398 break;
399
400 case 'X':
401 widget_main(WIDST_LOAD_PALETTE);
402 break;
403
404 case 'Z':
405 InitCurrentColors();
406 DefaultPalette();
407 redisplay(MESH);
408 break;
409
410 case 'F':
411 strcpy(saved_rules, active_rules);
412 widget_main(WIDST_LOAD_RULE);
413 break;
414
415 case '=':
416 case '+':
417 inc_scale();
418 break;
419
420 case '-':
421 dec_scale();
422 break;
423
424 case '.':
425 prep_tentative();
426 xpos += dx = SCALE(event.xbutton.x - width/2);
427 ypos += dy = SCALE(event.xbutton.y - height/2);
428 display_move(0, dx, dy);
429 break;
430
431 case 'g':
432 confirmload();
433 state = state == RUN ? STOP : RUN;
434 lastx--;
435 bounding_box(&active);
436 redraw_lifew();
437 break;
438
439 case '@':
440 if (ev_mode == VALENCE_DRIVEN || historymode) {
441 char s[100];
442 confirmload();
443 strcpy(s, active_rules);
444 if (historymode)
445 s[strlen(s) - 1] = 0;
446 else
447 strcat(s, "+");
448 file_rules(s);
449 }
450 else {
451 strcpy(inpbuf, "History is only allowed for 2-state automata");
452 announce_and_wait(RED_EVER);
453 displaystats();
454 }
455 break;
456
457 case 'H':
458 if (truehistory = !truehistory) {
459 confirmload();
460 clearhistorytiles();
461 pattern2history(&active, 0);
462 announce("History record mode is on");
463 }
464 else {
465 redisplay(0);
466 announce("History record mode is off");
467 }
468 break;
469
470 case 'c':
471 bounding_box(&active);
472 if (oscillators) {
473 osc_on_msg:
474 strcpy(inpbuf, "Oscillator check mode is on!");
475 announce_and_wait(RED_EVER);
476 }
477 else
478 dispboxes ^= 1;
479 displaystats();
480 break;
481
482 case '*':
483 dispspeed = !dispspeed;
484 displaystats();
485 break;
486
487 case '$':
488 bounding_box(&active);
489 if (oscillators)
490 goto osc_on_msg;
491 else
492 dispchanges ^= 1;
493 displaystats();
494 break;
495
496 case 'P':
497 if (oscillators ^= 1) {
498 save_dispboxes = dispboxes;
499 save_dispchanges = dispchanges;
500 dispboxes = dispchanges = 1;
501 confirmload();
502 copypattern(&active, &oscillator_check);
503 generate(&active);
504 generate(&oscillator_check);
505 oscillator_check.generations = active.generations;
506 strcpy(inpbuf, "Oscillator check mode is on!");
507 announce_and_wait(GREEN_EVER);
508 state = RUN;
509 }
510 else {
511 dispboxes = save_dispboxes;
512 dispchanges = save_dispchanges;
513 announce("Oscillator check mode is off");
514 }
515 break;
516
517 case 'E':
518 if ((pseudocolor = (pseudocolor + 1)%5) > 0) {
519 pseudopaint[0][1] = pseudocolor == 1 ? 0 : 2;
520 pseudopaint[1][0] = pseudocolor == 3 ? 1 : 3;
521 pseudopaint[1][1] = pseudocolor == 4 ? 0 : 1;
522 strcpy(inpbuf, "Pseudocolor mode: ");
523 pseudocolor_msg();
524 announce(inpbuf);
525 }
526 else
527 announce("Pseudocolor mode is off");
528 redisplay(MESH);
529 break;
530
531 case 'o':
532 num = tentative.tiles != 0;
533 confirmload();
534 generate(&active);
535 lastx--;
536 redisplay(num);
537 displaystats();
538 break;
539
540 case 'p':
541 if (dispcoord)
542 dispcoord = FALSE;
543 else
544 {
545 lastx--; /* fake move to force coordinates to print */
546 dispcoord = TRUE;
547 }
548 /* force resize of input window */
549 ResizeLW(height - INPUTH - BORDERWIDTH*3);
550 showrules();
551 break;
552
553 case 'n': {
554 coord_t sxpos = xpos, sypos = ypos;
555 prep_tentative();
556 current_tile();
557 display_move(0, xpos - sxpos, ypos - sypos);
558 break;
559 }
560
561 case '(':
562 case '[':
563 case '{':
564 for (num = 0; kbuf[0] != "([{"[num]; num++);
565 xmarker[num] = XPOS(event.xmotion.x);
566 ymarker[num] = YPOS(event.xmotion.y);
567 sprintf(inpbuf, "Marker %d set to (%d,%d)",
568 num, xmarker[num] - xorigin, ymarker[num] - yorigin);
569 DoExpose(inputw);
570 break;
571
572 case ')':
573 case ']':
574 case '}':
575 for (num = 0; kbuf[0] != ")]}"[num]; num++);
576 xpos += xmarker[num] - XPOS(event.xmotion.x);
577 ypos += ymarker[num] - XPOS(event.xmotion.y);
578 redraw_lifew();
579 break;
580
581 case 'J':
582 announce("Jump to x, y: ");
583 minbuflen = 14;
584 getxstring();
585 {
586 int x, y;
587 if (sscanf(inpbuf + 13, "%d, %d", &x, &y) == 2) {
588 xpos += x + xorigin - XPOS(event.xmotion.x);
589 ypos += y + yorigin - YPOS(event.xmotion.y);
590 redraw_lifew();
591 }
592 displaystats();
593 }
594 break;
595
596 case 'T':
597 confirmload();
598 announce("Enter topology: ");
599 minbuflen = 16;
600 getxstring();
601 if (!inpbuf[16])
602 goto exit_T;
603 {
604 char s[80];
605 strcpy(s, inpbuf + 16);
606 strncpy(inpbuf, " Wrong topology ", 16);
607 if (set_topology(s) > 0) {
608 announce_and_wait(RED_EVER);
609 goto exit_T;
610 }
611 }
612 fixpatterntopology();
613 redraw_lifew();
614 showrules();
615 exit_T:
616 displaystats();
617 break;
618
619 case 'j':
620 announce("Enter jump length: ");
621 minbuflen = 19;
622 getxstring();
623 {
624 unsigned x;
625 if (sscanf(inpbuf + 19, "%u", &x) == 1 && x < 200000 && x > 0)
626 hideperiod = x;
627 }
628 if (hideperiod < 2)
629 strcpy(inpbuf, "No jump");
630 else
631 sprintf(inpbuf, "Jump set to %u", hideperiod);
632 DoExpose(inputw);
633 break;
634
635 case 'O':
636 announce("Origin set to active cell");
637 xorigin = XPOS(event.xmotion.x);
638 yorigin = YPOS(event.xmotion.y);
639 showcoord(1);
640 break;
641
642 case 'Y':
643 if (tentative.tiles) {
644 clear_pattern(&active);
645 copy_tentative();
646 clear_pattern(&tentative);
647 redraw_lifew();
648 displaystats();
649 }
650 break;
651
652 case 'C':
653 if (tentative.tiles)
654 clear_pattern(&tentative);
655 else {
656 setscale(scale = 3);
657 clear_pattern(&active);
658 free_loadscript();
659 numcomments = outcome[0] = 0;
660 speed = 0;
661 state = STOP;
662 displaystats();
663 center();
664 }
665 redraw_lifew();
666 break;
667
668 case 'S':
669 widget_main(WIDST_SAVE);
670 break;
671
672 case 'W':
673 /* Confirm latest load before saving script */
674 confirmload();
675 savex = XPOS(fix_mouse_coord(event.xmotion.x, width));
676 savey = YPOS(fix_mouse_coord(event.xmotion.y, height));
677 if (loadscript == loadscript->next) {
678 strcpy(inpbuf, "There is no script to save!");
679 announce_and_wait(RED_EVER);
680 displaystats();
681 }
682 else
683 widget_main(WIDST_SAVE_SCRIPT);
684 break;
685
686 case 'D':
687 free_loadscript();
688 numcomments = outcome[0] = 0;
689 if (tentative.tiles) {
690 clear_pattern(&tentative);
691 redraw_lifew();
692 announce("Load script (and latest load) discarded");
693 }
694 else
695 announce("Load script discarded");
696 break;
697
698 case 'l':
699 confirmload();
700 iloadx = loadx = XPOS(fix_mouse_coord(event.xmotion.x, width));
701 iloady = loady = YPOS(fix_mouse_coord(event.xmotion.y, height));
702 widget_main(WIDST_LOAD_PATTERN);
703 adjust_pivotpos();
704 break;
705
706 case 'L':
707 if (stashed[0]) {
708 confirmload();
709 iloadx = loadx = XPOS(fix_mouse_coord(event.xmotion.x, width));
710 iloady = loady = YPOS(fix_mouse_coord(event.xmotion.y, height));
711 strcpy(saved_rules, active_rules);
712 if (!loadfile_req(stashed)) {
713 sprintf(inpbuf, "Can't load %s", stashed);
714 goto ERROUT;
715 }
716 adjust_pivotpos();
717 if (rules_changed())
718 free_loadscript();
719 }
720 else {
721 strcpy(inpbuf, "No previous load");
722 ERROUT:
723 announce_and_wait(RED_EVER);
724 displaystats();
725 }
726 break;
727
728 case 'u':
729 prep_tentative();
730 txx = tyy = 1;
731 txy = tyx = 0;
732 loadx = iloadx;
733 loady = iloady;
734 display_move(0, 0, 0);
735 break;
736
737 case 'h':
738 confirmload();
739 if (state == HIDE) {
740 state = RUN;
741 redraw_lifew();
742 }
743 else
744 state = HIDE;
745 break;
746
747 case '/':
748 view_slashinfo();
749 break;
750
751 case 'b':
752 if (bounding_box(&active) == 0)
753 sprintf(inpbuf, "Life is extinct");
754 else
755 sprintf(inpbuf,
756 "Life bounds: %d <= x <= %d %d <= y <= %d",
757 active.xmin - xorigin, active.xmax - xorigin,
758 active.ymin - yorigin, active.ymax - yorigin);
759 announce_and_wait(0);
760 displaystats();
761 break;
762
763 case '?':
764 help();
765 break;
766
767 case 'f':
768 settimeout(delay = DELAY_FAST);
769 break;
770
771 case 'm':
772 settimeout(delay = DELAY_MED);
773 break;
774
775 case 's':
776 settimeout(delay = DELAY_SLOW);
777 break;
778
779 case '>':
780 if (delay >= DELAY_INCREMENT)
781 settimeout(delay -= DELAY_INCREMENT);
782 break;
783
784 case '<':
785 settimeout(delay += DELAY_INCREMENT);
786 break;
787
788 case '!':
789 randomize();
790 break;
791
792 case '%': {
793 float r;
794 announce("Input density (% or nothing): ");
795 minbuflen = 30;
796 getxstring();
797 if (sscanf(inpbuf + 30, "%f", &r) == 1)
798 rnd_density = r/100;
799 sprintf(inpbuf, "Using %.2f%% density", rnd_density*100);
800 DoExpose(inputw);
801 }
802 break;
803
804 case 'i': /* set evolution counter */
805 announce("Number of generations to perform (default = infinite): ");
806 minbuflen = 55;
807 getxstring();
808 if (sscanf(inpbuf + 55, "%u", &runcounter) != 1)
809 runcounter = 0;
810 displaystats();
811 break;
812
813 case '#': /* toggle wireframe tentative pattern mode */
814 strcpy(inpbuf, "Wireframe mode is o");
815 if (wireframe ^= 1)
816 strcat(inpbuf, "n");
817 else
818 strcat(inpbuf, "ff");
819 DoExpose(inputw);
820 if (tentative.tiles)
821 redraw_lifew();
822 break;
823
824 case 'M': /* toggle gridmode */
825 dispmesh ^= 1;
826 redraw_lifew();
827 break;
828
829 case '^': {
830 unsigned x = 0;
831 announce("Set random seed (integer number): ");
832 minbuflen = 17;
833 getxstring();
834 if (sscanf(inpbuf + 16, "%u", &x) == 1)
835 srandom(randomseed = x);
836 sprintf(inpbuf, "Random seed is set to %u", x);
837 DoExpose(inputw);
838 }
839 break;
840
841 case 'N':
842 name_file();
843 break;
844
845 case 'A':
846 comment();
847 break;
848
849 case 'V':
850 view_comments();
851 break;
852
853 case 'K':
854 numcomments = outcome[0] = 0;
855 announce("Comments are discarded");
856 break;
857
858 case 'k':
859 num = lookcell(&active, XPOS(event.xmotion.x), YPOS(event.xmotion.y));
860 setcolor(num, 0, 0);
861 break;
862
863 case 'v':
864 viewvars();
865 break;
866
867 case 'B':
868 benchmark();
869 bounding_box(&active);
870 break;
871
872 case 'Q':
873 //XCloseDisplay(disp);
874 exit(0);
875
876 case 'U': /* Get rid of loaded pattern */
877 if (stashed[0]) {
878 clear_pattern(&tentative);
879 redraw_lifew();
880 }
881 break;
882
883 case 'I': /* Force confirm of loaded pattern */
884 confirmload();
885 display_move(1, 0, 0);
886 break;
887
888 case 'd':
889 copy_tentative();
890 break;
891
892 case 'G': /* perform some generations on loaded pattern */
893 prep_tentative();
894 genload();
895 lastx--;
896 bounding_box(&active);
897 display_move(0, 0, 0);
898 break;
899
900 case 'x':
901 if (tentative.tiles) {
902 long dlx, dly, tx, ty;
903 prep_tentative();
904 clipboard_copy(&tentative);
905 loadx += dlx = XPOS(event.xbutton.x) - loadx;
906 loady += dly = YPOS(event.xbutton.y) - loady;
907 iloadx += tx = (dly*txy - dlx*tyy)/(txy*tyx - txx*tyy);
908 iloady += ty = (dlx*tyx - dly*txx)/(txy*tyx - txx*tyy);
909 clipboard.x -= tx;
910 clipboard.y -= ty;
911 clear_pattern(&tentative);
912 clipboard_flush(&tentative, maxstates);
913 }
914 break;
915
916 case 'a':
917 if (ev_mode == TABLE_DRIVEN || ev_mode == TAB8_DRIVEN)
918 set_transition();
919 break;
920 case 't':
921 if (ev_mode == TABLE_DRIVEN || ev_mode == TAB8_DRIVEN)
922 test_transition();
923 }
924 kbuf[0] = '\0'; /* get rid of old keystroke so shift doesn't bring it back */
925 }
926
cell2line(cell_t c)927 static int cell2line(cell_t c) {
928 if (chgcell(&active, linex, liney, c)) {
929 drawcell(RXPOS(linex), RYPOS(liney), c);
930 fb_ins_old(linex, liney, c);
931 return 1;
932 }
933 return 0;
934 }
935
Motion(void)936 void Motion(void) { /* handle X motion events */
937 if (event.xmotion.window == lifew) {
938 coord_t x = XPOS(event.xmotion.x), y = YPOS(event.xmotion.y);
939 if (tentative.tiles) {
940 if (event.xmotion.state & Button1MotionMask)
941 moveload();
942 return;
943 }
944 if (event.xmotion.state & Button1MotionMask) {
945 int changed = 0;
946 if (!fix_mouse_coord(event.xmotion.x, width) || !fix_mouse_coord(event.xmotion.y, height))
947 return;
948 while (abs(linex - x) > 0 || abs(liney - y) > 0) {
949 linex += sgn((int)(x - linex)), liney += sgn((int)(y - liney));
950 if (limits && !chk_limits(linex, liney))
951 break;
952 if (cell2line(paintcolor)) changed = 1;
953 }
954 if (changed) displaystats();
955 }
956 else if (event.xmotion.state & Button3MotionMask) {
957 /* erase the old box, draw the new one */
958 if (!limits || chk_limits(loadx, loady)) {
959 if (limits) {
960 if (limits&1)
961 if (x < x_min_limit)
962 x = x_min_limit;
963 else if (x >= x_max_limit)
964 x = x_max_limit - 1;
965 if (limits&2)
966 if (y < y_min_limit)
967 y = y_min_limit;
968 else if (y >= y_max_limit)
969 y = y_max_limit - 1;
970 }
971 if (savex != x || savey != y) {
972 erasebox(loadx, loady, savex, savey);
973 drawbox(loadx, loady, savex = x, savey = y, ORANGE_EVER);
974 }
975 }
976 }
977 else if (event.xmotion.state & Button2MotionMask) {
978 int changed = 0;
979 if (!fix_mouse_coord(event.xmotion.x, width) || !fix_mouse_coord(event.xmotion.y, height))
980 return;
981 while (abs(linex - x) > 0 || abs(liney - y) > 0) {
982 linex += sgn((int)(x - linex)), liney += sgn((int)(y - liney));
983 if (limits && !chk_limits(linex, liney))
984 break;
985 if (cell2line(0)) changed = 1;
986 }
987 if (changed) displaystats();
988 }
989 }
990 }
991
Button(void)992 void Button(void) { /* handle a button-press event */
993 if (event.xbutton.window == statew)
994 if (event.xbutton.button == 1)
995 setcolor(-1, event.xbutton.x, event.xbutton.y);
996 else
997 entercolor(event.xbutton.x, event.xbutton.y);
998 else if (event.xbutton.window == lifew) {
999 int dy;
1000 switch (event.xbutton.button) {
1001 case 5:
1002 prep_tentative();
1003 ypos += dy = (scale >= 0) ? 5 : 5 << -scale;
1004 display_move(0, 0, dy);
1005 return;
1006 case 4:
1007 prep_tentative();
1008 ypos -= dy = (scale >= 0) ? 5 : 5 << -scale;
1009 display_move(0, 0, -dy);
1010 return;
1011 }
1012 if (tentative.tiles)
1013 switch (event.xbutton.button) {
1014 case 1:
1015 moveload();
1016 break;
1017 case 2:
1018 flipload();
1019 break;
1020 case 3:
1021 turnload();
1022 }
1023 else {
1024 coord_t x = XPOS(event.xmotion.x), y = YPOS(event.xmotion.y);
1025 switch(event.xbutton.button) {
1026 case 1:
1027 if (!limits || chk_limits(x, y)) {
1028 showcoord(TRUE);
1029 linex = x, liney = y;
1030 if (cell2line(paintcolor)) displaystats();
1031 }
1032 break;
1033 case 2:
1034 if (!limits || chk_limits(x, y)) {
1035 showcoord(TRUE);
1036 linex = x, liney = y;
1037 if (cell2line(0)) displaystats();
1038 }
1039 break;
1040 case 3:
1041 savex = loadx = x;
1042 savey = loady = y;
1043 drawbox(x, y, x, y, ORANGE_EVER);
1044 }
1045 }
1046 }
1047 }
1048
Release()1049 void Release() {
1050 if (event.xbutton.window == lifew && !tentative.tiles
1051 && event.xbutton.button == 3) {
1052 int dx = 0, dy = 0;
1053 if (loadx == savex && savey == loady) {
1054 drawbox(loadx, loady, loadx, loady, 0);
1055 xpos += dx = SCALE(event.xbutton.x - width/2);
1056 ypos += dy = SCALE(event.xbutton.y - height/2);
1057 }
1058 else {
1059 make_tentative(loadx, loady, savex, savey);
1060 displaystats();
1061 }
1062 display_move(0, dx, dy);
1063 }
1064 }
1065
selectmainfont()1066 static XFontStruct* selectmainfont() {
1067 XFontStruct *f;
1068 char fontspec[80];
1069 if (f = XLoadQueryFont(disp, NORMALFONT)) return f;
1070 sprintf(fontspec, "-*-courier-medium-r-*--%d-*-*-*-*-*-*-*", FONTHEIGHT);
1071 if (f = XLoadQueryFont(disp, fontspec)) return f;
1072 sprintf(fontspec, "-*-courier-*-r-*--%d-*-*-*-*-*-*-*", FONTHEIGHT);
1073 if (f = XLoadQueryFont(disp, fontspec)) return f;
1074 return 0;
1075 }
1076
selectsmallfont()1077 static XFontStruct* selectsmallfont() {
1078 XFontStruct *f;
1079 if (f = XLoadQueryFont(disp, "6x9")) return f;
1080 if (f = XLoadQueryFont(disp, "-*-*-medium-r-*--9-*-*-*-*-*-*-*")) return f;
1081 if (f = XLoadQueryFont(disp, "-*-*-*-r-*--8-*-*-*-*-*-*-*")) return f;
1082 if (f = XLoadQueryFont(disp, "-*-courier-bold-r-*--8-*-*-*-*-*-*-*")) return f;
1083 if (f = XLoadQueryFont(disp, "-*-*-medium-r-*--10-*-*-*-*-*-*-*")) return f;
1084 if (f = XLoadQueryFont(disp, "-*-*-*-r-*--9-*-*-*-*-*-*-*")) return f;
1085 if (f = XLoadQueryFont(disp, "-*-*-medium-r-*--11-*-*-*-*-*-*-*")) return f;
1086 if (f = XLoadQueryFont(disp, "-*-*-medium-r-*--12-*-*-*-*-*-*-*")) return f;
1087 if (f = XLoadQueryFont(disp, "*6x*")) return f;
1088 if (f = XLoadQueryFont(disp, "*7x*")) return f;
1089 return selectmainfont();
1090 }
1091
make_delay(long sec,long msec)1092 void make_delay(long sec, long msec) {
1093 struct timeval inputdelay;
1094 inputdelay.tv_sec = sec;
1095 inputdelay.tv_usec = msec;
1096 select(32, 0, 0, 0, &inputdelay);
1097 }
1098
check_param(int b)1099 static int check_param(int b) {
1100 if (b)
1101 fatal("Usage: xlife [-display disp] [-geometry geom] [-l pattern-lib] [filename]\n");
1102 return 1;
1103 }
1104
init_load(char * initpat)1105 static void init_load(char *initpat) {
1106 char *s = checktilda(initpat);
1107 if (s == 0) return;
1108 loadx = xpos;
1109 loady = ypos;
1110 txx = tyy = 1;
1111 txy = tyx = 0;
1112 if (loadfile_req(s))
1113 adjust_pivotpos();
1114 }
1115
1116 #ifdef MICROSOFT
wmain(int argc,char ** argv)1117 int wmain(int argc, char **argv) {
1118 #else
1119 int main(int argc, char **argv) {
1120 #endif
1121 int i, qgens = 0;
1122 Cursor cursor;
1123 Pixmap icon, cursor_data, cursor_mask;
1124 XSizeHints hints;
1125 XWMHints wm_hints;
1126 XClassHint class_hints;
1127 XSetWindowAttributes winat;
1128 XColor white, black;
1129 char *geomstring = 0;
1130 char *initpat = 0;
1131 XTextProperty iconName;
1132 unsigned long cwhite, cblack;
1133 char *icon_name = "Xlife";
1134 char *display = getenv("DISPLAY");
1135
1136 if (strstr(argv[0], "lifeconv")) {
1137 saveformat = 0;
1138 convmode++;
1139 for (i = 1; i < argc; i++)
1140 if (*argv[i] == '-')
1141 if (strchr("ACDIMPRSpv?lg4", argv[i][1]))
1142 switch (argv[i][1]) {
1143 case '?':
1144 le: fatal("Usage: lifeconv -ACDIMPRSpv? [-l pattern-lib] [-g n] filename\n");
1145 case 'v':
1146 printf("Lifeconv/XLife v%d.%d.%d\n", majorversion,
1147 minorversion, patchlevel);
1148 return 0;
1149 case 'g':
1150 if (argc <= i + 1 || sscanf(argv[++i], "%d", &qgens) != 1) goto le;
1151 break;
1152 case 'l':
1153 if (argc <= i + 1) goto le;
1154 strcpy(matchlibfile, argv[++i]);
1155 break;
1156 case 'p':
1157 oldp++;
1158 argv[i][1] = 'P';
1159 default:
1160 if (saveformat != 0) goto le;
1161 saveformat = argv[i][1];
1162 }
1163 else
1164 goto le;
1165 else if (initpat == 0)
1166 initpat = argv[i];
1167 }
1168 else
1169 for (i = 1; i < argc; i++)
1170 if (!strcmp(argv[i], "-geometry") && check_param(argc <= i + 1))
1171 geomstring = argv[++i];
1172 else if (!strcmp(argv[i], "-l") && check_param(argc <= i + 1))
1173 strcpy(matchlibfile, argv[++i]);
1174 else if (!strcmp(argv[i], "-display") && check_param(argc <= i + 1))
1175 display = argv[++i];
1176 else if (*argv[i] != '-')
1177 initpat = argv[i];
1178 if (convmode && (initpat == 0 || saveformat == 0)) goto le;
1179 if (!getcwd(inidir, PATNAMESIZ))
1180 fatal("Too long dirname\n");
1181 if (!display)
1182 fatal("No display defined!\n");
1183 if (!(disp = XOpenDisplay(display)))
1184 fatal("Can't open X display\n");
1185 if (XDefaultDepth(disp, screen) < STATEBITS)
1186 fatal("Not enough colors for compiled STATEBITS value\n");
1187 #if VFREQ != 0
1188 gettimeofday(&prev_vsync, 0);
1189 #endif
1190 setcurdir(LIFEDIR); /*inidir*/
1191 fileinit();
1192 initcells(&active);
1193 initcells(&tentative);
1194 xpos = xorigin = lastx = STARTX;
1195 ypos = yorigin = lasty = STARTY;
1196 dispcoord = TRUE;
1197 dispchanges = dispboxes = FALSE;
1198 state = STOP;
1199 gentab();
1200 srandom(time(0));
1201
1202 screen = DefaultScreen(disp);
1203 rootw = RootWindow(disp, screen);
1204 fcolor = cwhite = WhitePixel(disp, screen);
1205 bcolor = cblack = BlackPixel(disp, screen);
1206
1207 hints.x = hints.y = 0;
1208 maxwidth = width = DisplayWidth(disp, screen);
1209 inputlength = width/FONTWIDTH;
1210 height = DisplayHeight(disp, screen);
1211 if ((pfb = malloc(i = height*width*sizeof(struct FB))) == 0)
1212 fatal("Not enough memory for the framebuffer");
1213 else
1214 memset(pfb, 0, i);
1215 hints.width = width*GRAB_FRACTION;
1216 hints.height = height*GRAB_FRACTION;
1217 hints.flags = PPosition | PSize;
1218 if (geomstring) {
1219 int result = XParseGeometry(geomstring, &hints.x, &hints.y,
1220 (unsigned*)&hints.width, (unsigned*)&hints.height);
1221 if (result & XNegative)
1222 hints.x += (DisplayWidth(disp, screen) - hints.width)*GRAB_FRACTION;
1223 if (result & YNegative)
1224 hints.y += (DisplayHeight(disp, screen) - hints.height)*GRAB_FRACTION;
1225 if (result & XValue || result & YValue) {
1226 hints.flags |= USPosition;
1227 hints.flags &= ~PPosition;
1228 }
1229 if (result & WidthValue || result & HeightValue) {
1230 hints.flags |= USSize;
1231 hints.flags &= ~PSize;
1232 }
1233 }
1234 mainw = XCreateSimpleWindow(disp, rootw,
1235 hints.x, hints.y, hints.width, hints.height, 0, fcolor, bcolor);
1236 if (!mainw)
1237 fatal("Can't open main window\n");
1238 icon = XCreateBitmapFromData(disp, mainw, icon_bits, icon_width, icon_height);
1239 if (XStringListToTextProperty(&icon_name, 1, &iconName) == 0)
1240 fatal("structure allocation for iconName failed.\n");
1241 wm_hints.initial_state = NormalState;
1242 wm_hints.input = True;
1243 wm_hints.icon_pixmap = icon;
1244 wm_hints.flags = IconPixmapHint | StateHint | InputHint;
1245 class_hints.res_name = argv[0];
1246 class_hints.res_class = "Basicwin";
1247 XSetWMProperties(disp, mainw, 0, &iconName, argv, argc, &hints, &wm_hints, &class_hints);
1248 IniPalette();
1249 black = cellcolor[0];
1250 white = cellcolor[1];
1251 /* text display is forced to black on white */
1252 xgcv.background = cwhite;
1253 xgcv.foreground = cblack;
1254 ntextgc = XCreateGC(disp, mainw, GCForeground | GCBackground, &xgcv);
1255 xgcv.background = cblack;
1256 xgcv.foreground = cwhite;
1257 itextgc = XCreateGC(disp, mainw, GCForeground | GCBackground, &xgcv);
1258 /* create XOR GC for pivot display */
1259 xgcv.foreground = cellcolor[CYAN_EVER].pixel;
1260 xgcv.function = GXxor;
1261 xorgc = XCreateGC(disp, mainw, GCForeground | GCFunction, &xgcv);
1262 if (!(nfont = selectmainfont()))
1263 fatal("Can't load font\n");
1264 XSetFont(disp, ntextgc, nfont->fid);
1265 XSetFont(disp, itextgc, nfont->fid);
1266 XSetFont(disp, cellgc[LOADW_BG], nfont->fid);
1267 XSetFont(disp, xorgc, nfont->fid);
1268 cfont = selectsmallfont();
1269 xgcv.function = GXxor;
1270 xgcv.foreground = cellcolor[ORANGE_EVER].pixel;
1271 invgc = XCreateGC(disp, mainw, GCForeground | GCFunction, &xgcv);
1272 XSetFont(disp, invgc, cfont->fid);
1273 cursor_data = XCreateBitmapFromData(disp, mainw, cursor_data_bits,
1274 cursor_data_width, cursor_data_height);
1275 cursor_mask = XCreateBitmapFromData(disp, mainw, cursor_mask_bits,
1276 cursor_mask_width, cursor_mask_height);
1277 cursor = XCreatePixmapCursor(disp, cursor_data, cursor_mask, &white,
1278 &black, cursor_data_x_hot, cursor_data_y_hot);
1279 XDefineCursor(disp, mainw, cursor);
1280 width = hints.width;
1281 height = hints.height;
1282 set_active_rules("life", 0);
1283 lifew = XCreateSimpleWindow(disp, mainw,
1284 0, 0, width - BORDERWIDTH*2,
1285 height - INPUTH - BORDERWIDTH*3, BORDERWIDTH, fcolor, bcolor);
1286 helpw = XCreateSimpleWindow(disp, mainw,
1287 0, 0, width - BORDERWIDTH*2, height - BORDERWIDTH*2,
1288 BORDERWIDTH, cwhite, cblack);
1289 coordw = XCreateSimpleWindow(disp, mainw,
1290 width - COORDW - BORDERWIDTH*2,
1291 height - INPUTH - BORDERWIDTH*2,
1292 COORDW, INPUTH, BORDERWIDTH, cblack, cwhite);
1293 rulew = XCreateSimpleWindow(disp, mainw,
1294 width - COORDW - rulew_len - BORDERWIDTH*2,
1295 height - INPUTH - BORDERWIDTH*2,
1296 rulew_len, INPUTH, BORDERWIDTH, cblack, cwhite);
1297 statew = XCreateSimpleWindow(disp, mainw,
1298 width, BORDERWIDTH, 1, INPUTH, BORDERWIDTH,
1299 cblack, cwhite);
1300 loadw = XCreateSimpleWindow(disp, mainw,
1301 50, /*LOADW_HEIGHT + 50 > height ? 0 : 40*/4, LOADW_WIDTH, LOADW_HEIGHT, BORDERWIDTH,
1302 cblack, cellcolor[LOADW_BG].pixel);
1303 inputw = XCreateSimpleWindow(disp, mainw, 0,
1304 height - INPUTH - BORDERWIDTH*2, width - BORDERWIDTH*2,
1305 INPUTH, BORDERWIDTH, cblack, cwhite);
1306 winat.win_gravity = SouthGravity;
1307 XChangeWindowAttributes(disp, inputw, CWWinGravity, &winat);
1308 XSelectInput(disp, mainw,
1309 #ifndef MICROSOFT
1310 KeyPressMask |
1311 #endif
1312 ExposureMask | StructureNotifyMask);
1313 XSelectInput(disp, inputw, ButtonPressMask | ExposureMask);
1314 XSelectInput(disp, lifew, KeyPressMask | ButtonPressMask | Button1MotionMask
1315 | PointerMotionMask | Button3MotionMask | ButtonReleaseMask | ExposureMask);
1316 XSelectInput(disp, helpw, KeyPressMask | ButtonPressMask | ExposureMask);
1317 XSelectInput(disp, rulew, ExposureMask);
1318 XSelectInput(disp, statew, ExposureMask | ButtonPressMask);
1319 XSelectInput(disp, loadw, KeyPressMask | ExposureMask | ButtonPressMask
1320 | PointerMotionMask | LeaveWindowMask);
1321 XSelectInput(disp, coordw, ExposureMask);
1322 alloc_states(VALENCE_DRIVEN, 2);
1323 setscale(scale = 3);
1324 settimeout(delay = DELAY_FAST);
1325 /*
1326 * Only accept one pattern since it is highly unlikely that overlaying
1327 * n patterns is what you want to do
1328 */
1329 if (saveformat == 'C') {
1330 collect(initpat, 0);
1331 return 0;
1332 }
1333 if (convmode) {
1334 init_load(initpat);
1335 i = bounding_box(&tentative);
1336 confirmload();
1337 if (i != bounding_box(&active))
1338 fatal("Can't automatically convert this pattern with topology information -- Use XLife for the conversion\n");
1339 while (qgens-- > 0)
1340 generate(&active);
1341 #ifdef MICROSOFT
1342 /* MINGW can't use stdout :-( */
1343 {
1344 FILE *f = fopen(argv[argc - 1], "r");
1345 if (f || argc < 4)
1346 errwin: fatalw("Wrong name for the output file. Use syntax: lifeconv OPTIONS INFILE OUTFILE");
1347 f = fopen(argv[argc - 1], "w");
1348 if (!f) goto errwin;
1349 saveall(f, saveformat);
1350 fclose(f);
1351 }
1352 #else
1353 saveall(stdout, saveformat);
1354 #endif
1355 return 0;
1356 }
1357 xpos -= SCALE(width >> 1);
1358 ypos -= SCALE(height >> 1);
1359 XMapWindow(disp, inputw);
1360 XMapWindow(disp, helpw);
1361 XMapWindow(disp, lifew);
1362 XMapWindow(disp, mainw);
1363 XMapWindow(disp, rulew);
1364 XMapWindow(disp, statew);
1365 XMapWindow(disp, loadw);
1366 XMapWindow(disp, coordw);
1367 XLowerWindow(disp, helpw);
1368 XLowerWindow(disp, statew);
1369 XLowerWindow(disp, loadw);
1370 XRaiseWindow(disp, inputw);
1371 XRaiseWindow(disp, rulew);
1372 XRaiseWindow(disp, coordw);
1373 showrules();
1374 displaystats();
1375 if (initpat)
1376 init_load(initpat);
1377 #ifdef MICROSOFT
1378 griddisplay(1);
1379 #endif
1380 for (;;) {
1381 while (XCheckMaskEvent(disp, KeyPressMask|ButtonPressMask|Button1MotionMask
1382 |PointerMotionMask|Button3MotionMask|ButtonReleaseMask|ExposureMask
1383 |StructureNotifyMask, &event)) {
1384 switch(event.type) {
1385 case KeyPress:
1386 XLookupString(&event.xkey, keybuf, 16, &ks, 0);
1387 if (!DoKeySymIn(ks))
1388 if (event.xkey.window == lifew || !strchr("(){}[].JOkx", *keybuf))
1389 DoKeyIn(keybuf);
1390 break;
1391 case MotionNotify:
1392 /* don't allow drawing until load is confirmed */
1393 Motion();
1394 break;
1395 case ButtonPress:
1396 Button();
1397 break;
1398 case ButtonRelease:
1399 Release();
1400 break;
1401 case ConfigureNotify:
1402 DoResize();
1403 redraw_lifew();
1404 break;
1405 case Expose:
1406 DoExpose(event.xexpose.window);
1407 }
1408 }
1409 showcoord(FALSE);
1410 if (state != STOP) {
1411 generate(&active);
1412 if (hideperiod > 1) {
1413 for (i = 1; i < hideperiod; i++)
1414 if (state != STOP)
1415 generate(&active);
1416 if (state != HIDE)
1417 redisplay(0);
1418 }
1419 else
1420 redisplay(0);
1421 if (speed < 10000*hideperiod || ((active.generations/hideperiod)&0x3f) == 0)
1422 displaystats();
1423 }
1424 else
1425 make_delay(0, 100000);
1426 if (state == RUN)
1427 make_delay(timeout.tv_sec, timeout.tv_usec);
1428 }
1429 }
1430 /* main.c ends here */
1431