ftp://ftp.ntnu.no/old/pub/X11/R5contrib/xscreensaver-1.17.tar.gz
[xscreensaver] / hacks / maze.c
1 /******************************************************************************
2  * [ maze ] ...
3  *
4  * modified:  [ 3-7-93 ]  Jamie Zawinski <jwz@lucid.com>
5  *              added the XRoger logo, cleaned up resources, made
6  *              grid size a parameter.
7  * modified:  [ 3-3-93 ]  Jim Randell <jmr@mddjmr.fc.hp.com>
8  *              Added the colour stuff and integrated it with jwz's
9  *              screenhack stuff.  There's still some work that could
10  *              be done on this, particularly allowing a resource to
11  *              specify how big the squares are.
12  * modified:  [ 10-4-88 ]  Richard Hess    ...!uunet!cimshop!rhess  
13  *              [ Revised primary execution loop within main()...
14  *              [ Extended X event handler, check_events()...
15  * modified:  [ 1-29-88 ]  Dave Lemke      lemke@sun.com  
16  *              [ Hacked for X11...
17  *              [  Note the word "hacked" -- this is extremely ugly, but at 
18  *              [   least it does the job.  NOT a good programming example 
19  *              [   for X.
20  * original:  [ 6/21/85 ]  Martin Weiss    Sun Microsystems  [ SunView ]
21  *
22  ******************************************************************************
23  Copyright 1988 by Sun Microsystems, Inc. Mountain View, CA.
24   
25  All Rights Reserved
26   
27  Permission to use, copy, modify, and distribute this software and its
28  documentation for any purpose and without fee is hereby granted, 
29  provided that the above copyright notice appear in all copies and that
30  both that copyright notice and this permission notice appear in 
31  supporting documentation, and that the names of Sun or MIT not be
32  used in advertising or publicity pertaining to distribution of the
33  software without specific prior written permission. Sun and M.I.T. 
34  make no representations about the suitability of this software for 
35  any purpose. It is provided "as is" without any express or implied warranty.
36  
37  SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39  PURPOSE. IN NO EVENT SHALL SUN BE LIABLE FOR ANY SPECIAL, INDIRECT
40  OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
41  OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
42  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
43  OR PERFORMANCE OF THIS SOFTWARE.
44  *****************************************************************************/
45
46 #include "screenhack.h"
47
48 #define XROGER
49
50 static int solve_delay, pre_solve_delay, post_solve_delay;
51
52 #include  <stdio.h>
53 #include  <X11/Xlib.h>
54 #include  <X11/Xutil.h>
55 #include  <X11/bitmaps/gray1>
56
57 #define MAX_MAZE_SIZE_X 500
58 #define MAX_MAZE_SIZE_Y 500
59
60 #define MOVE_LIST_SIZE  (MAX_MAZE_SIZE_X * MAX_MAZE_SIZE_Y)
61
62 #define WALL_TOP        0x8000
63 #define WALL_RIGHT      0x4000
64 #define WALL_BOTTOM     0x2000
65 #define WALL_LEFT       0x1000
66
67 #define DOOR_IN_TOP     0x800
68 #define DOOR_IN_RIGHT   0x400
69 #define DOOR_IN_BOTTOM  0x200
70 #define DOOR_IN_LEFT    0x100
71 #define DOOR_IN_ANY     0xF00
72
73 #define DOOR_OUT_TOP    0x80
74 #define DOOR_OUT_RIGHT  0x40
75 #define DOOR_OUT_BOTTOM 0x20
76 #define DOOR_OUT_LEFT   0x10
77
78 #define START_SQUARE    0x2
79 #define END_SQUARE      0x1
80
81 #define border_x        (0)
82 #define border_y        (0)
83
84 #define get_random(x)   (random() % (x))
85   
86 static int logo_x, logo_y;
87
88 #ifdef XROGER
89 # define logo_width  128
90 # define logo_height 128
91 #else
92 # include  <X11/bitmaps/xlogo64>
93 # define logo_width xlogo64_width
94 # define logo_height xlogo64_height
95 # define logo_bits xlogo64_bits
96 #endif
97
98 static unsigned short maze[MAX_MAZE_SIZE_X][MAX_MAZE_SIZE_Y];
99
100 static struct {
101   unsigned char x;
102   unsigned char y;
103   unsigned char dir;
104 } move_list[MOVE_LIST_SIZE], save_path[MOVE_LIST_SIZE], path[MOVE_LIST_SIZE];
105
106 static int maze_size_x, maze_size_y;
107 static int sqnum, cur_sq_x, cur_sq_y, path_length;
108 static int start_x, start_y, start_dir, end_x, end_y, end_dir;
109 static int maze_restart_flag, random_index;
110 static int grid_width, grid_height;
111
112 static Display  *dpy;
113 static Window   win;
114 static GC       gc, cgc, tgc, logo_gc;
115 static Pixmap   logo_map;
116
117 static int      x = 0, y = 0, restart = 0, stop = 1, state = 1;
118
119 check_events()                                  /* X event handler [ rhess ] */
120 {
121   XEvent        e;
122
123   if (XPending(dpy)) {
124     XNextEvent(dpy, &e);
125     switch (e.type) {
126
127     case ButtonPress:
128       switch (e.xbutton.button) {
129       case 3:
130         exit (0);
131         break;
132       case 2:
133         stop = !stop ;
134         if (state == 5) state = 4 ;
135         else {
136           restart = 1;
137           stop = 0;
138         }
139         break;
140       default:
141         restart = 1 ;
142         stop = 0 ;
143         break;
144       }
145       break;
146
147     case ConfigureNotify:
148       restart = 1;
149       break;
150     case UnmapNotify:
151       stop = 1;
152       XClearWindow (dpy, win);
153       XSync (dpy, False);
154       break;
155     case Expose:
156       restart = 1;
157       break;
158     }
159     return(1);
160   }
161   return(0);
162 }
163
164
165 set_maze_sizes (width, height)
166      int width, height;
167 {
168   maze_size_x = width / grid_width;
169   maze_size_y = height / grid_height;
170 }
171
172
173 initialize_maze()         /* draw the surrounding wall and start/end squares */
174 {
175   register int i, j, wall;
176   
177   /* initialize all squares */
178   for ( i=0; i<maze_size_x; i++) {
179     for ( j=0; j<maze_size_y; j++) {
180       maze[i][j] = 0;
181     }
182   }
183   
184   /* top wall */
185   for ( i=0; i<maze_size_x; i++ ) {
186     maze[i][0] |= WALL_TOP;
187   }
188   
189   /* right wall */
190   for ( j=0; j<maze_size_y; j++ ) {
191     maze[maze_size_x-1][j] |= WALL_RIGHT;
192   }
193   
194   /* bottom wall */
195   for ( i=0; i<maze_size_x; i++ ) {
196     maze[i][maze_size_y-1] |= WALL_BOTTOM;
197   }
198   
199   /* left wall */
200   for ( j=0; j<maze_size_y; j++ ) {
201     maze[0][j] |= WALL_LEFT;
202   }
203   
204   /* set start square */
205   wall = get_random(4);
206   switch (wall) {
207   case 0:       
208     i = get_random(maze_size_x);
209     j = 0;
210     break;
211   case 1:       
212     i = maze_size_x - 1;
213     j = get_random(maze_size_y);
214     break;
215   case 2:       
216     i = get_random(maze_size_x);
217     j = maze_size_y - 1;
218     break;
219   case 3:       
220     i = 0;
221     j = get_random(maze_size_y);
222     break;
223   }
224   maze[i][j] |= START_SQUARE;
225   maze[i][j] |= ( DOOR_IN_TOP >> wall );
226   maze[i][j] &= ~( WALL_TOP >> wall );
227   cur_sq_x = i;
228   cur_sq_y = j;
229   start_x = i;
230   start_y = j;
231   start_dir = wall;
232   sqnum = 0;
233   
234   /* set end square */
235   wall = (wall + 2)%4;
236   switch (wall) {
237   case 0:
238     i = get_random(maze_size_x);
239     j = 0;
240     break;
241   case 1:
242     i = maze_size_x - 1;
243     j = get_random(maze_size_y);
244     break;
245   case 2:
246     i = get_random(maze_size_x);
247     j = maze_size_y - 1;
248     break;
249   case 3:
250     i = 0;
251     j = get_random(maze_size_y);
252     break;
253   }
254   maze[i][j] |= END_SQUARE;
255   maze[i][j] |= ( DOOR_OUT_TOP >> wall );
256   maze[i][j] &= ~( WALL_TOP >> wall );
257   end_x = i;
258   end_y = j;
259   end_dir = wall;
260   
261   /* set logo */
262   if ((maze_size_x > 15) && (maze_size_y > 15))
263     {
264       int logow = 1 + logo_width / grid_width;
265       int logoh = 1 + logo_height / grid_height;
266       /* not closer than 3 grid units from a wall */
267       logo_x = get_random (maze_size_x - logow - 6) + 3;
268       logo_y = get_random (maze_size_y - logoh - 6) + 3;
269       for (i=0; i<logow; i++)
270         for (j=0; j<logoh; j++)
271           maze[logo_x + i][logo_y + j] |= DOOR_IN_TOP;
272     }
273   else
274     logo_y = logo_x = -1;
275 }
276
277 static int choose_door ();
278 static int backup ();
279 static void draw_wall ();
280 static void draw_solid_square ();
281 static void enter_square ();
282
283 create_maze()             /* create a maze layout given the intiialized maze */
284 {
285   register int i, newdoor;
286   
287   do {
288     move_list[sqnum].x = cur_sq_x;
289     move_list[sqnum].y = cur_sq_y;
290     move_list[sqnum].dir = newdoor;
291     while ( ( newdoor = choose_door() ) == -1 ) { /* pick a door */
292       if ( backup() == -1 ) { /* no more doors ... backup */
293         return; /* done ... return */
294       }
295     }
296     
297     /* mark the out door */
298     maze[cur_sq_x][cur_sq_y] |= ( DOOR_OUT_TOP >> newdoor );
299     
300     switch (newdoor) {
301     case 0: cur_sq_y--;
302       break;
303     case 1: cur_sq_x++;
304       break;
305     case 2: cur_sq_y++;
306       break;
307     case 3: cur_sq_x--;
308       break;
309     }
310     sqnum++;
311     
312     /* mark the in door */
313     maze[cur_sq_x][cur_sq_y] |= ( DOOR_IN_TOP >> ((newdoor+2)%4) );
314     
315     /* if end square set path length and save path */
316     if ( maze[cur_sq_x][cur_sq_y] & END_SQUARE ) {
317       path_length = sqnum;
318       for ( i=0; i<path_length; i++) {
319         save_path[i].x = move_list[i].x;
320         save_path[i].y = move_list[i].y;
321         save_path[i].dir = move_list[i].dir;
322       }
323     }
324     
325   } while (1);
326   
327 }
328
329
330 static int
331 choose_door()                                            /* pick a new path */
332 {
333   int candidates[3];
334   register int num_candidates;
335   
336   num_candidates = 0;
337   
338  topwall:
339   /* top wall */
340   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_TOP )
341     goto rightwall;
342   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_TOP )
343     goto rightwall;
344   if ( maze[cur_sq_x][cur_sq_y] & WALL_TOP )
345     goto rightwall;
346   if ( maze[cur_sq_x][cur_sq_y - 1] & DOOR_IN_ANY ) {
347     maze[cur_sq_x][cur_sq_y] |= WALL_TOP;
348     maze[cur_sq_x][cur_sq_y - 1] |= WALL_BOTTOM;
349     draw_wall(cur_sq_x, cur_sq_y, 0);
350     goto rightwall;
351   }
352   candidates[num_candidates++] = 0;
353   
354  rightwall:
355   /* right wall */
356   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_RIGHT )
357     goto bottomwall;
358   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_RIGHT )
359     goto bottomwall;
360   if ( maze[cur_sq_x][cur_sq_y] & WALL_RIGHT )
361     goto bottomwall;
362   if ( maze[cur_sq_x + 1][cur_sq_y] & DOOR_IN_ANY ) {
363     maze[cur_sq_x][cur_sq_y] |= WALL_RIGHT;
364     maze[cur_sq_x + 1][cur_sq_y] |= WALL_LEFT;
365     draw_wall(cur_sq_x, cur_sq_y, 1);
366     goto bottomwall;
367   }
368   candidates[num_candidates++] = 1;
369   
370  bottomwall:
371   /* bottom wall */
372   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_BOTTOM )
373     goto leftwall;
374   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_BOTTOM )
375     goto leftwall;
376   if ( maze[cur_sq_x][cur_sq_y] & WALL_BOTTOM )
377     goto leftwall;
378   if ( maze[cur_sq_x][cur_sq_y + 1] & DOOR_IN_ANY ) {
379     maze[cur_sq_x][cur_sq_y] |= WALL_BOTTOM;
380     maze[cur_sq_x][cur_sq_y + 1] |= WALL_TOP;
381     draw_wall(cur_sq_x, cur_sq_y, 2);
382     goto leftwall;
383   }
384   candidates[num_candidates++] = 2;
385   
386  leftwall:
387   /* left wall */
388   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_LEFT )
389     goto donewall;
390   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_LEFT )
391     goto donewall;
392   if ( maze[cur_sq_x][cur_sq_y] & WALL_LEFT )
393     goto donewall;
394   if ( maze[cur_sq_x - 1][cur_sq_y] & DOOR_IN_ANY ) {
395     maze[cur_sq_x][cur_sq_y] |= WALL_LEFT;
396     maze[cur_sq_x - 1][cur_sq_y] |= WALL_RIGHT;
397     draw_wall(cur_sq_x, cur_sq_y, 3);
398     goto donewall;
399   }
400   candidates[num_candidates++] = 3;
401   
402  donewall:
403   if (num_candidates == 0)
404     return ( -1 );
405   if (num_candidates == 1)
406     return ( candidates[0] );
407   return ( candidates[ get_random(num_candidates) ] );
408   
409 }
410
411
412 static int
413 backup()                                                  /* back up a move */
414 {
415   sqnum--;
416   cur_sq_x = move_list[sqnum].x;
417   cur_sq_y = move_list[sqnum].y;
418   return ( sqnum );
419 }
420
421
422 draw_maze_border()                                  /* draw the maze outline */
423 {
424   register int i, j;
425   
426   
427   for ( i=0; i<maze_size_x; i++) {
428     if ( maze[i][0] & WALL_TOP ) {
429       XDrawLine(dpy, win, gc,
430                 border_x + grid_width * i,
431                 border_y,
432                 border_x + grid_width * (i+1) - 1,
433                 border_y);
434     }
435     if ((maze[i][maze_size_y - 1] & WALL_BOTTOM)) {
436       XDrawLine(dpy, win, gc,
437                 border_x + grid_width * i,
438                 border_y + grid_height * (maze_size_y) - 1,
439                 border_x + grid_width * (i+1) - 1,
440                 border_y + grid_height * (maze_size_y) - 1);
441     }
442   }
443   for ( j=0; j<maze_size_y; j++) {
444     if ( maze[maze_size_x - 1][j] & WALL_RIGHT ) {
445       XDrawLine(dpy, win, gc,
446                 border_x + grid_width * maze_size_x - 1,
447                 border_y + grid_height * j,
448                 border_x + grid_width * maze_size_x - 1,
449                 border_y + grid_height * (j+1) - 1);
450     }
451     if ( maze[0][j] & WALL_LEFT ) {
452       XDrawLine(dpy, win, gc,
453                 border_x,
454                 border_y + grid_height * j,
455                 border_x,
456                 border_y + grid_height * (j+1) - 1);
457     }
458   }
459   
460   if (logo_x != -1)
461     {
462       Window r;
463       int x, y;
464       unsigned int w, h, bw, d;
465       XGetGeometry (dpy, logo_map, &r, &x, &y, &w, &h, &bw, &d);
466       XCopyPlane (dpy, logo_map, win, logo_gc,
467                   0, 0, w, h,
468                   border_x + 3 + grid_width * logo_x,
469                   border_y + 3 + grid_height * logo_y, 1);
470     }
471   draw_solid_square (start_x, start_y, start_dir, tgc);
472   draw_solid_square (end_x, end_y, end_dir, tgc);
473 }
474
475
476 static void
477 draw_wall(i, j, dir)                                   /* draw a single wall */
478      int i, j, dir;
479 {
480   switch (dir) {
481   case 0:
482     XDrawLine(dpy, win, gc,
483               border_x + grid_width * i, 
484               border_y + grid_height * j,
485               border_x + grid_width * (i+1), 
486               border_y + grid_height * j);
487     break;
488   case 1:
489     XDrawLine(dpy, win, gc,
490               border_x + grid_width * (i+1), 
491               border_y + grid_height * j,
492               border_x + grid_width * (i+1), 
493               border_y + grid_height * (j+1));
494     break;
495   case 2:
496     XDrawLine(dpy, win, gc,
497               border_x + grid_width * i, 
498               border_y + grid_height * (j+1),
499               border_x + grid_width * (i+1), 
500               border_y + grid_height * (j+1));
501     break;
502   case 3:
503     XDrawLine(dpy, win, gc,
504               border_x + grid_width * i, 
505               border_y + grid_height * j,
506               border_x + grid_width * i, 
507               border_y + grid_height * (j+1));
508     break;
509   }
510 }
511
512 int bw;
513
514 static void
515 draw_solid_square(i, j, dir, gc)          /* draw a solid square in a square */
516      register int i, j, dir;
517      GC gc;
518 {
519   switch (dir) {
520   case 0: XFillRectangle(dpy, win, gc,
521                          border_x + bw + grid_width * i, 
522                          border_y - bw + grid_height * j, 
523                          grid_width - (bw+bw), grid_height);
524     break;
525   case 1: XFillRectangle(dpy, win, gc,
526                          border_x + bw + grid_width * i, 
527                          border_y + bw + grid_height * j, 
528                          grid_width, grid_height - (bw+bw));
529     break;
530   case 2: XFillRectangle(dpy, win, gc,
531                          border_x + bw + grid_width * i, 
532                          border_y + bw + grid_height * j, 
533                          grid_width - (bw+bw), grid_height);
534     break;
535   case 3: XFillRectangle(dpy, win, gc,
536                          border_x - bw + grid_width * i, 
537                          border_y + bw + grid_height * j, 
538                          grid_width, grid_height - (bw+bw));
539     break;
540   }
541   XSync (dpy, False);
542 }
543
544
545 solve_maze()                             /* solve it with graphical feedback */
546 {
547   int i;
548   
549   
550   /* plug up the surrounding wall */
551   maze[start_x][start_y] |= (WALL_TOP >> start_dir);
552   maze[end_x][end_y] |= (WALL_TOP >> end_dir);
553   
554   /* initialize search path */
555   i = 0;
556   path[i].x = end_x;
557   path[i].y = end_y;
558   path[i].dir = -1;
559   
560   /* do it */
561   while (1) {
562     if ( ++path[i].dir >= 4 ) {
563       i--;
564       draw_solid_square( (int)(path[i].x), (int)(path[i].y), 
565                         (int)(path[i].dir), cgc);
566     }
567     else if ( ! (maze[path[i].x][path[i].y] & 
568                  (WALL_TOP >> path[i].dir))  && 
569              ( (i == 0) || ( (path[i].dir != 
570                               (int)(path[i-1].dir+2)%4) ) ) ) {
571       enter_square(i);
572       i++;
573       if ( maze[path[i].x][path[i].y] & START_SQUARE ) {
574         return;
575       }
576     } 
577     if (check_events()) return;
578     /* Abort solve on expose - cheapo repaint strategy */
579     if (solve_delay) usleep (solve_delay);
580   }
581
582
583
584 static void
585 enter_square(n)                            /* move into a neighboring square */
586      int n;
587 {
588   draw_solid_square( (int)path[n].x, (int)path[n].y, 
589                     (int)path[n].dir, tgc);
590   
591   path[n+1].dir = -1;
592   switch (path[n].dir) {
593   case 0: path[n+1].x = path[n].x;
594     path[n+1].y = path[n].y - 1;
595     break;
596   case 1: path[n+1].x = path[n].x + 1;
597     path[n+1].y = path[n].y;
598     break;
599   case 2: path[n+1].x = path[n].x;
600     path[n+1].y = path[n].y + 1;
601     break;
602   case 3: path[n+1].x = path[n].x - 1;
603     path[n+1].y = path[n].y;
604     break;
605   }
606 }
607
608 /* ----<eof> */
609
610
611 /*
612  *  jmr additions for Jamie Zawinski's <jwz@lucid.com> screensaver stuff,
613  *  note that the code above this has probably been hacked about in some
614  *  arbitrary way.
615  */
616
617 char *progclass = "Maze";
618
619 char *defaults[] = {
620   "*gridSize:   0",
621   "*background: black",
622   "*solveDelay: 5000",
623   "*preDelay:   2000000",
624   "*postDelay:  4000000",
625   "*liveColor:  green",
626   "*deadColor:  red",
627 #ifdef XROGER
628   "*logoColor:  red3",
629 #endif
630   0
631 };
632
633 XrmOptionDescRec options[] = {
634   { "-grid-size",       ".gridSize",    XrmoptionSepArg, 0 },
635   { "-solve-delay",     ".solveDelay",  XrmoptionSepArg, 0 },
636   { "-pre-delay",       ".preDelay",    XrmoptionSepArg, 0 },
637   { "-post-delay",      ".postDelay",   XrmoptionSepArg, 0 },
638   { "-live-color",      ".liveColor",   XrmoptionSepArg, 0 },
639   { "-dead-color",      ".deadColor",   XrmoptionSepArg, 0 }
640 };
641
642 int options_size = (sizeof(options)/sizeof(options[0]));
643
644 void screenhack(display,window)
645      Display *display;
646      Window window;
647 {
648   Pixmap gray;
649   int size, root;
650   XWindowAttributes xgwa;
651   unsigned long bg, fg, pfg, pbg, lfg;
652
653   size = get_integer_resource ("gridSize", "Dimension");
654   root = get_boolean_resource("root", "Boolean");
655   solve_delay = get_integer_resource ("solveDelay", "Integer");
656   pre_solve_delay = get_integer_resource ("preDelay", "Integer");
657   post_solve_delay = get_integer_resource ("postDelay", "Integer");
658
659   if (size < 2) size = 7 + (random () % 30);
660   grid_width = grid_height = size;
661   bw = (size > 6 ? 3 : (size-1)/2);
662
663   dpy = display; win = window; /* the maze stuff uses global variables */
664
665   XGetWindowAttributes (dpy, win, &xgwa);
666
667   x = 0;
668   y = 0;
669
670   set_maze_sizes (xgwa.width, xgwa.height);
671
672   if (! root)
673     XSelectInput (dpy, win, ExposureMask|ButtonPressMask|StructureNotifyMask);
674   
675   gc = XCreateGC(dpy, win, 0, 0);
676   cgc = XCreateGC(dpy, win, 0, 0);
677   tgc = XCreateGC(dpy,win,0,0);
678   logo_gc = XCreateGC(dpy, win, 0, 0);
679   
680   gray = XCreateBitmapFromData (dpy,win,gray1_bits,gray1_width,gray1_height);
681
682   bg  = get_pixel_resource ("background","Background", dpy, xgwa.colormap);
683   fg  = get_pixel_resource ("foreground","Foreground", dpy, xgwa.colormap);
684   lfg = get_pixel_resource ("logoColor", "Foreground", dpy, xgwa.colormap);
685   pfg = get_pixel_resource ("liveColor", "Foreground", dpy, xgwa.colormap);
686   pbg = get_pixel_resource ("deadColor", "Foreground", dpy, xgwa.colormap);
687   if (mono_p) lfg = pfg = fg;
688
689   if (lfg == bg)
690     lfg = ((bg == WhitePixel (dpy, DefaultScreen (dpy)))
691            ? BlackPixel (dpy, DefaultScreen (dpy))
692            : WhitePixel (dpy, DefaultScreen (dpy)));
693
694   XSetForeground (dpy, gc, fg);
695   XSetBackground (dpy, gc, bg);
696   XSetForeground (dpy, cgc, pbg);
697   XSetBackground (dpy, cgc, bg);
698   XSetForeground (dpy, tgc, pfg);
699   XSetBackground (dpy, tgc, bg);
700   XSetForeground (dpy, logo_gc, lfg);
701   XSetBackground (dpy, logo_gc, bg);
702
703   XSetStipple (dpy, cgc, gray);
704   XSetFillStyle (dpy, cgc, FillOpaqueStippled);
705   
706 #ifdef XROGER
707   {
708     int w, h;
709     XGCValues gcv;
710     GC draw_gc, erase_gc;
711     extern void skull ();
712     /* round up to grid size */
713     w = ((logo_width  / grid_width) + 1)  * grid_width;
714     h = ((logo_height / grid_height) + 1) * grid_height;
715     logo_map = XCreatePixmap (dpy, win, w, h, 1);
716     gcv.foreground = 1L;
717     draw_gc = XCreateGC (dpy, logo_map, GCForeground, &gcv);
718     gcv.foreground = 0L;
719     erase_gc= XCreateGC (dpy, logo_map, GCForeground, &gcv);
720     XFillRectangle (dpy, logo_map, erase_gc, 0, 0, w, h);
721     skull (dpy, logo_map, draw_gc, erase_gc, 5, 0, w-10, h-10);
722     XFreeGC (dpy, draw_gc);
723     XFreeGC (dpy, erase_gc);
724   }
725 #else
726   if  (!(logo_map = XCreateBitmapFromData (dpy, win, logo_bits,
727                                            logo_width, logo_height)))
728     {
729       fprintf (stderr, "Can't create logo pixmap\n");
730       exit (1);
731     }
732 #endif
733   XMapRaised(dpy, win);
734   srandom(getpid());
735
736   restart = root;
737
738   while (1) {                            /* primary execution loop [ rhess ] */
739     if (check_events()) continue ;
740     if (restart || stop) goto pop;
741     switch (state) {
742     case 1:
743       initialize_maze();
744       break;
745     case 2:
746       XClearWindow(dpy, win);
747       draw_maze_border();
748       break;
749     case 3:
750       create_maze();
751       break;
752     case 4:
753       XSync (dpy, False);
754       usleep (pre_solve_delay);
755       break;
756     case 5:
757       solve_maze();
758       break;
759     case 6:
760       XSync (dpy, False);
761       usleep (post_solve_delay);
762       state = 0 ;
763       break;
764     default:
765       abort ();
766     }
767     ++state;
768   pop:
769     if (restart)
770       {
771         static XWindowAttributes wattr;
772         restart = 0;
773         stop = 0;
774         state = 1;
775         XGetWindowAttributes (dpy, win, &wattr);
776         set_maze_sizes (wattr.width, wattr.height);
777         XClearWindow (dpy, win);
778         XSync (dpy, False);
779       }
780   }
781 }