1 /******************************************************************************
4 * modified: [ 3-7-93 ] Jamie Zawinski <jwz@mcom.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
17 * [ Note the word "hacked" -- this is extremely ugly, but at
18 * [ least it does the job. NOT a good programming example
20 * original: [ 6/21/85 ] Martin Weiss Sun Microsystems [ SunView ]
22 ******************************************************************************
23 Copyright 1988 by Sun Microsystems, Inc. Mountain View, CA.
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.
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 *****************************************************************************/
46 #include "screenhack.h"
50 static int solve_delay, pre_solve_delay, post_solve_delay;
54 #include <X11/Xutil.h>
56 #include <X11/bitmaps/gray1>
58 #include "sys$common:[decw$include.bitmaps]gray1.xbm"
61 #define MAX_MAZE_SIZE_X 500
62 #define MAX_MAZE_SIZE_Y 500
64 #define MOVE_LIST_SIZE (MAX_MAZE_SIZE_X * MAX_MAZE_SIZE_Y)
66 #define WALL_TOP 0x8000
67 #define WALL_RIGHT 0x4000
68 #define WALL_BOTTOM 0x2000
69 #define WALL_LEFT 0x1000
71 #define DOOR_IN_TOP 0x800
72 #define DOOR_IN_RIGHT 0x400
73 #define DOOR_IN_BOTTOM 0x200
74 #define DOOR_IN_LEFT 0x100
75 #define DOOR_IN_ANY 0xF00
77 #define DOOR_OUT_TOP 0x80
78 #define DOOR_OUT_RIGHT 0x40
79 #define DOOR_OUT_BOTTOM 0x20
80 #define DOOR_OUT_LEFT 0x10
82 #define START_SQUARE 0x2
83 #define END_SQUARE 0x1
88 #define get_random(x) (random() % (x))
90 static int logo_x, logo_y;
93 # define logo_width 128
94 # define logo_height 128
97 # include <X11/bitmaps/xlogo64>
99 # include "sys$common:[decw$include.bitmaps]xlogo64.xbm"
101 # define logo_width xlogo64_width
102 # define logo_height xlogo64_height
103 # define logo_bits xlogo64_bits
106 static unsigned short maze[MAX_MAZE_SIZE_X][MAX_MAZE_SIZE_Y];
112 } move_list[MOVE_LIST_SIZE], save_path[MOVE_LIST_SIZE], path[MOVE_LIST_SIZE];
114 static int maze_size_x, maze_size_y;
115 static int sqnum, cur_sq_x, cur_sq_y, path_length;
116 static int start_x, start_y, start_dir, end_x, end_y, end_dir;
117 static int grid_width, grid_height;
121 static GC gc, cgc, tgc, logo_gc;
122 static Pixmap logo_map;
124 static int x = 0, y = 0, restart = 0, stop = 1, state = 1;
127 check_events() /* X event handler [ rhess ] */
136 switch (e.xbutton.button) {
142 if (state == 5) state = 4 ;
155 case ConfigureNotify:
160 XClearWindow (dpy, win);
174 set_maze_sizes (width, height)
177 maze_size_x = width / grid_width;
178 maze_size_y = height / grid_height;
183 initialize_maze() /* draw the surrounding wall and start/end squares */
185 register int i, j, wall;
187 /* initialize all squares */
188 for ( i=0; i<maze_size_x; i++) {
189 for ( j=0; j<maze_size_y; j++) {
195 for ( i=0; i<maze_size_x; i++ ) {
196 maze[i][0] |= WALL_TOP;
200 for ( j=0; j<maze_size_y; j++ ) {
201 maze[maze_size_x-1][j] |= WALL_RIGHT;
205 for ( i=0; i<maze_size_x; i++ ) {
206 maze[i][maze_size_y-1] |= WALL_BOTTOM;
210 for ( j=0; j<maze_size_y; j++ ) {
211 maze[0][j] |= WALL_LEFT;
214 /* set start square */
215 wall = get_random(4);
218 i = get_random(maze_size_x);
223 j = get_random(maze_size_y);
226 i = get_random(maze_size_x);
231 j = get_random(maze_size_y);
234 maze[i][j] |= START_SQUARE;
235 maze[i][j] |= ( DOOR_IN_TOP >> wall );
236 maze[i][j] &= ~( WALL_TOP >> wall );
248 i = get_random(maze_size_x);
253 j = get_random(maze_size_y);
256 i = get_random(maze_size_x);
261 j = get_random(maze_size_y);
264 maze[i][j] |= END_SQUARE;
265 maze[i][j] |= ( DOOR_OUT_TOP >> wall );
266 maze[i][j] &= ~( WALL_TOP >> wall );
272 if ((maze_size_x > 15) && (maze_size_y > 15))
274 int logow = 1 + logo_width / grid_width;
275 int logoh = 1 + logo_height / grid_height;
276 /* not closer than 3 grid units from a wall */
277 logo_x = get_random (maze_size_x - logow - 6) + 3;
278 logo_y = get_random (maze_size_y - logoh - 6) + 3;
279 for (i=0; i<logow; i++)
280 for (j=0; j<logoh; j++)
281 maze[logo_x + i][logo_y + j] |= DOOR_IN_TOP;
284 logo_y = logo_x = -1;
287 static int choose_door ();
288 static int backup ();
289 static void draw_wall ();
290 static void draw_solid_square ();
291 static void enter_square ();
294 create_maze() /* create a maze layout given the intiialized maze */
296 register int i, newdoor;
299 move_list[sqnum].x = cur_sq_x;
300 move_list[sqnum].y = cur_sq_y;
301 move_list[sqnum].dir = newdoor;
302 while ( ( newdoor = choose_door() ) == -1 ) { /* pick a door */
303 if ( backup() == -1 ) { /* no more doors ... backup */
304 return; /* done ... return */
308 /* mark the out door */
309 maze[cur_sq_x][cur_sq_y] |= ( DOOR_OUT_TOP >> newdoor );
323 /* mark the in door */
324 maze[cur_sq_x][cur_sq_y] |= ( DOOR_IN_TOP >> ((newdoor+2)%4) );
326 /* if end square set path length and save path */
327 if ( maze[cur_sq_x][cur_sq_y] & END_SQUARE ) {
329 for ( i=0; i<path_length; i++) {
330 save_path[i].x = move_list[i].x;
331 save_path[i].y = move_list[i].y;
332 save_path[i].dir = move_list[i].dir;
342 choose_door() /* pick a new path */
345 register int num_candidates;
350 if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_TOP )
352 if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_TOP )
354 if ( maze[cur_sq_x][cur_sq_y] & WALL_TOP )
356 if ( maze[cur_sq_x][cur_sq_y - 1] & DOOR_IN_ANY ) {
357 maze[cur_sq_x][cur_sq_y] |= WALL_TOP;
358 maze[cur_sq_x][cur_sq_y - 1] |= WALL_BOTTOM;
359 draw_wall(cur_sq_x, cur_sq_y, 0);
362 candidates[num_candidates++] = 0;
366 if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_RIGHT )
368 if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_RIGHT )
370 if ( maze[cur_sq_x][cur_sq_y] & WALL_RIGHT )
372 if ( maze[cur_sq_x + 1][cur_sq_y] & DOOR_IN_ANY ) {
373 maze[cur_sq_x][cur_sq_y] |= WALL_RIGHT;
374 maze[cur_sq_x + 1][cur_sq_y] |= WALL_LEFT;
375 draw_wall(cur_sq_x, cur_sq_y, 1);
378 candidates[num_candidates++] = 1;
382 if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_BOTTOM )
384 if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_BOTTOM )
386 if ( maze[cur_sq_x][cur_sq_y] & WALL_BOTTOM )
388 if ( maze[cur_sq_x][cur_sq_y + 1] & DOOR_IN_ANY ) {
389 maze[cur_sq_x][cur_sq_y] |= WALL_BOTTOM;
390 maze[cur_sq_x][cur_sq_y + 1] |= WALL_TOP;
391 draw_wall(cur_sq_x, cur_sq_y, 2);
394 candidates[num_candidates++] = 2;
398 if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_LEFT )
400 if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_LEFT )
402 if ( maze[cur_sq_x][cur_sq_y] & WALL_LEFT )
404 if ( maze[cur_sq_x - 1][cur_sq_y] & DOOR_IN_ANY ) {
405 maze[cur_sq_x][cur_sq_y] |= WALL_LEFT;
406 maze[cur_sq_x - 1][cur_sq_y] |= WALL_RIGHT;
407 draw_wall(cur_sq_x, cur_sq_y, 3);
410 candidates[num_candidates++] = 3;
413 if (num_candidates == 0)
415 if (num_candidates == 1)
416 return ( candidates[0] );
417 return ( candidates[ get_random(num_candidates) ] );
423 backup() /* back up a move */
426 cur_sq_x = move_list[sqnum].x;
427 cur_sq_y = move_list[sqnum].y;
433 draw_maze_border() /* draw the maze outline */
438 for ( i=0; i<maze_size_x; i++) {
439 if ( maze[i][0] & WALL_TOP ) {
440 XDrawLine(dpy, win, gc,
441 border_x + grid_width * i,
443 border_x + grid_width * (i+1) - 1,
446 if ((maze[i][maze_size_y - 1] & WALL_BOTTOM)) {
447 XDrawLine(dpy, win, gc,
448 border_x + grid_width * i,
449 border_y + grid_height * (maze_size_y) - 1,
450 border_x + grid_width * (i+1) - 1,
451 border_y + grid_height * (maze_size_y) - 1);
454 for ( j=0; j<maze_size_y; j++) {
455 if ( maze[maze_size_x - 1][j] & WALL_RIGHT ) {
456 XDrawLine(dpy, win, gc,
457 border_x + grid_width * maze_size_x - 1,
458 border_y + grid_height * j,
459 border_x + grid_width * maze_size_x - 1,
460 border_y + grid_height * (j+1) - 1);
462 if ( maze[0][j] & WALL_LEFT ) {
463 XDrawLine(dpy, win, gc,
465 border_y + grid_height * j,
467 border_y + grid_height * (j+1) - 1);
475 unsigned int w, h, bw, d;
476 XGetGeometry (dpy, logo_map, &r, &x, &y, &w, &h, &bw, &d);
477 XCopyPlane (dpy, logo_map, win, logo_gc,
479 border_x + 3 + grid_width * logo_x,
480 border_y + 3 + grid_height * logo_y, 1);
482 draw_solid_square (start_x, start_y, start_dir, tgc);
483 draw_solid_square (end_x, end_y, end_dir, tgc);
488 draw_wall(i, j, dir) /* draw a single wall */
493 XDrawLine(dpy, win, gc,
494 border_x + grid_width * i,
495 border_y + grid_height * j,
496 border_x + grid_width * (i+1),
497 border_y + grid_height * j);
500 XDrawLine(dpy, win, gc,
501 border_x + grid_width * (i+1),
502 border_y + grid_height * j,
503 border_x + grid_width * (i+1),
504 border_y + grid_height * (j+1));
507 XDrawLine(dpy, win, gc,
508 border_x + grid_width * i,
509 border_y + grid_height * (j+1),
510 border_x + grid_width * (i+1),
511 border_y + grid_height * (j+1));
514 XDrawLine(dpy, win, gc,
515 border_x + grid_width * i,
516 border_y + grid_height * j,
517 border_x + grid_width * i,
518 border_y + grid_height * (j+1));
526 draw_solid_square(i, j, dir, gc) /* draw a solid square in a square */
527 register int i, j, dir;
531 case 0: XFillRectangle(dpy, win, gc,
532 border_x + bw + grid_width * i,
533 border_y - bw + grid_height * j,
534 grid_width - (bw+bw), grid_height);
536 case 1: XFillRectangle(dpy, win, gc,
537 border_x + bw + grid_width * i,
538 border_y + bw + grid_height * j,
539 grid_width, grid_height - (bw+bw));
541 case 2: XFillRectangle(dpy, win, gc,
542 border_x + bw + grid_width * i,
543 border_y + bw + grid_height * j,
544 grid_width - (bw+bw), grid_height);
546 case 3: XFillRectangle(dpy, win, gc,
547 border_x - bw + grid_width * i,
548 border_y + bw + grid_height * j,
549 grid_width, grid_height - (bw+bw));
557 solve_maze() /* solve it with graphical feedback */
562 /* plug up the surrounding wall */
563 maze[start_x][start_y] |= (WALL_TOP >> start_dir);
564 maze[end_x][end_y] |= (WALL_TOP >> end_dir);
566 /* initialize search path */
574 if ( ++path[i].dir >= 4 ) {
576 draw_solid_square( (int)(path[i].x), (int)(path[i].y),
577 (int)(path[i].dir), cgc);
579 else if ( ! (maze[path[i].x][path[i].y] &
580 (WALL_TOP >> path[i].dir)) &&
581 ( (i == 0) || ( (path[i].dir !=
582 (int)(path[i-1].dir+2)%4) ) ) ) {
585 if ( maze[path[i].x][path[i].y] & START_SQUARE ) {
589 if (check_events()) return;
590 /* Abort solve on expose - cheapo repaint strategy */
591 if (solve_delay) usleep (solve_delay);
597 enter_square(n) /* move into a neighboring square */
600 draw_solid_square( (int)path[n].x, (int)path[n].y,
601 (int)path[n].dir, tgc);
604 switch (path[n].dir) {
605 case 0: path[n+1].x = path[n].x;
606 path[n+1].y = path[n].y - 1;
608 case 1: path[n+1].x = path[n].x + 1;
609 path[n+1].y = path[n].y;
611 case 2: path[n+1].x = path[n].x;
612 path[n+1].y = path[n].y + 1;
614 case 3: path[n+1].x = path[n].x - 1;
615 path[n+1].y = path[n].y;
624 * jmr additions for Jamie Zawinski's <jwz@mcom.com> screensaver stuff,
625 * note that the code above this has probably been hacked about in some
629 char *progclass = "Maze";
632 "Maze.background: black", /* to placate SGI */
633 "Maze.foreground: white", /* to placate SGI */
636 "*preDelay: 2000000",
637 "*postDelay: 4000000",
646 XrmOptionDescRec options[] = {
647 { "-grid-size", ".gridSize", XrmoptionSepArg, 0 },
648 { "-solve-delay", ".solveDelay", XrmoptionSepArg, 0 },
649 { "-pre-delay", ".preDelay", XrmoptionSepArg, 0 },
650 { "-post-delay", ".postDelay", XrmoptionSepArg, 0 },
651 { "-live-color", ".liveColor", XrmoptionSepArg, 0 },
652 { "-dead-color", ".deadColor", XrmoptionSepArg, 0 }
655 int options_size = (sizeof(options)/sizeof(options[0]));
657 void screenhack(display,window)
663 XWindowAttributes xgwa;
664 unsigned long bg, fg, pfg, pbg, lfg;
666 size = get_integer_resource ("gridSize", "Dimension");
667 root = get_boolean_resource("root", "Boolean");
668 solve_delay = get_integer_resource ("solveDelay", "Integer");
669 pre_solve_delay = get_integer_resource ("preDelay", "Integer");
670 post_solve_delay = get_integer_resource ("postDelay", "Integer");
672 if (size < 2) size = 7 + (random () % 30);
673 grid_width = grid_height = size;
674 bw = (size > 6 ? 3 : (size-1)/2);
676 dpy = display; win = window; /* the maze stuff uses global variables */
678 XGetWindowAttributes (dpy, win, &xgwa);
683 set_maze_sizes (xgwa.width, xgwa.height);
686 XSelectInput (dpy, win, ExposureMask|ButtonPressMask|StructureNotifyMask);
688 gc = XCreateGC(dpy, win, 0, 0);
689 cgc = XCreateGC(dpy, win, 0, 0);
690 tgc = XCreateGC(dpy,win,0,0);
691 logo_gc = XCreateGC(dpy, win, 0, 0);
693 gray = XCreateBitmapFromData (dpy,win,gray1_bits,gray1_width,gray1_height);
695 bg = get_pixel_resource ("background","Background", dpy, xgwa.colormap);
696 fg = get_pixel_resource ("foreground","Foreground", dpy, xgwa.colormap);
697 lfg = get_pixel_resource ("logoColor", "Foreground", dpy, xgwa.colormap);
698 pfg = get_pixel_resource ("liveColor", "Foreground", dpy, xgwa.colormap);
699 pbg = get_pixel_resource ("deadColor", "Foreground", dpy, xgwa.colormap);
700 if (mono_p) lfg = pfg = fg;
703 lfg = ((bg == WhitePixel (dpy, DefaultScreen (dpy)))
704 ? BlackPixel (dpy, DefaultScreen (dpy))
705 : WhitePixel (dpy, DefaultScreen (dpy)));
707 XSetForeground (dpy, gc, fg);
708 XSetBackground (dpy, gc, bg);
709 XSetForeground (dpy, cgc, pbg);
710 XSetBackground (dpy, cgc, bg);
711 XSetForeground (dpy, tgc, pfg);
712 XSetBackground (dpy, tgc, bg);
713 XSetForeground (dpy, logo_gc, lfg);
714 XSetBackground (dpy, logo_gc, bg);
716 XSetStipple (dpy, cgc, gray);
717 XSetFillStyle (dpy, cgc, FillOpaqueStippled);
723 GC draw_gc, erase_gc;
724 extern void skull ();
725 /* round up to grid size */
726 w = ((logo_width / grid_width) + 1) * grid_width;
727 h = ((logo_height / grid_height) + 1) * grid_height;
728 logo_map = XCreatePixmap (dpy, win, w, h, 1);
730 draw_gc = XCreateGC (dpy, logo_map, GCForeground, &gcv);
732 erase_gc= XCreateGC (dpy, logo_map, GCForeground, &gcv);
733 XFillRectangle (dpy, logo_map, erase_gc, 0, 0, w, h);
734 skull (dpy, logo_map, draw_gc, erase_gc, 5, 0, w-10, h-10);
735 XFreeGC (dpy, draw_gc);
736 XFreeGC (dpy, erase_gc);
739 if (!(logo_map = XCreateBitmapFromData (dpy, win, logo_bits,
740 logo_width, logo_height)))
742 fprintf (stderr, "Can't create logo pixmap\n");
746 XMapRaised(dpy, win);
751 while (1) { /* primary execution loop [ rhess ] */
752 if (check_events()) continue ;
753 if (restart || stop) goto pop;
759 XClearWindow(dpy, win);
767 usleep (pre_solve_delay);
774 usleep (post_solve_delay);
784 static XWindowAttributes wattr;
788 XGetWindowAttributes (dpy, win, &wattr);
789 set_maze_sizes (wattr.width, wattr.height);
790 XClearWindow (dpy, win);