1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* puzzle --- the familiar Sam Loyd puzzle */
3
4 #if 0
5 static const char sccsid[] = "@(#)puzzle.c 5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /*-
10 * Copyright (c) 1995 by Heath Rice <rice@asl.dl.nec.com>.
11 *
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
17 *
18 * This file is provided AS IS with no warranties of any kind. The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof. In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
23 *
24 * Revision History:
25 * 01-Nov-2000: Allocation checks
26 * 20-Mar-1998: Ideas from slip.c and eyes.c, problems with XGetImage when
27 * image moved off screen (-inwindow or -debug).
28 * 10-May-1997: Compatible with xscreensaver
29 * 15-Mar-1996: cleaned up, NUMBERED compile-time switch is now broken.
30 * Feb-1996: combined with rastering. Jouk Jansen <joukj AT hrem.nano.tudelft.nl>.
31 * Feb-1995: written. Heath Rice <hrice@netcom.com>
32 */
33
34 /*-
35 * Chops up the screen into squares and randomly slides them around
36 * like that game where you try to rearrange the little tiles in their
37 * original order. After it scrambles the tiles for awhile, it reverses
38 * itself and puts them back like they started. This mode looks the coolest
39 * if you have a picture on your background.
40 */
41
42 #ifdef STANDALONE
43 #define MODE_puzzle
44 #define DEFAULTS "*delay: 10000 \n" \
45 "*count: 250 \n" \
46 "*ncolors: 64 \n" \
47 "*bitmap: \n" \
48
49 # define free_puzzle 0
50 # define reshape_puzzle 0
51 # define puzzle_handle_event 0
52 # define UNIFORM_COLORS
53 #include "xlockmore.h" /* in xscreensaver distribution */
54 static XImage blogo =
55 {
56 0, 0, /* width, height */
57 0, XYBitmap, 0, /* xoffset, format, data */
58 LSBFirst, 8, /* byte-order, bitmap-unit */
59 LSBFirst, 8, 1 /* bitmap-bit-order, bitmap-pad, depth */
60 };
61 #else /* STANDALONE */
62 #include "xlock.h" /* in xlockmore distribution */
63 #include "color.h"
64 #include "iostuff.h"
65 #endif /* STANDALONE */
66
67 #ifdef MODE_puzzle
68
69 ENTRYPOINT ModeSpecOpt puzzle_opts =
70 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
71
72 #ifdef USE_MODULES
73 ModStruct puzzle_description =
74 {"puzzle", "init_puzzle", "draw_puzzle", "release_puzzle",
75 "init_puzzle", "init_puzzle", (char *) NULL, &puzzle_opts,
76 10000, 250, 1, 1, 64, 1.0, "",
77 "Shows a puzzle being scrambled and then solved", 0, NULL};
78
79 #endif
80
81 #ifdef STANDALONE
82 #define PUZZLE_WIDTH xscreensaver_width
83 #define PUZZLE_HEIGHT xscreensaver_height
84 #define PUZZLE_BITS xscreensaver_bits
85 #include "bitmaps/xscreensaver.xbm"
86 #else
87 #define PUZZLE_WIDTH image_width
88 #define PUZZLE_HEIGHT image_height
89 #define PUZZLE_BITS image_bits
90 #include "puzzle.xbm"
91 #endif
92
93 #ifdef HAVE_XPM
94 #ifdef STANDALONE
95 #include <X11/xpm.h>
96 #define PUZZLE_NAME xscreensaver
97 #include "pixmaps/xscreensaver.xpm"
98 #else
99 #define PUZZLE_NAME image_name
100 #include "puzzle.xpm"
101 #endif
102 #define DEFAULT_XPM 1
103 #endif
104
105 #define NOWAY 255
106
107 /*int storedmoves, *moves, *position, space; To keep track of puzzle */
108 typedef struct {
109 Bool painted; /* For debouncing */
110 int excount;
111 int *fixbuff;
112 XPoint count, boxsize, windowsize;
113 XPoint usablewindow, offsetwindow;
114 XPoint randompos, randpos;
115 unsigned long black;
116 int row, col, nextrow, nextcol, nextbox;
117 int incrementOfMove;
118 int lastbox;
119 int forward;
120 int prev;
121 int moves;
122
123 /* Delta move stuff */
124 int movingBox;
125 Pixmap bufferBox;
126 int cfactor, rfactor;
127 int Lp;
128 int cbs, cbw, rbs, rbw;
129 int lengthOfMove;
130
131 #ifdef NUMBERED
132 XImage *image;
133 GC gc;
134 /* Font stuff */
135 int done;
136 int ascent, fontWidth, fontHeight;
137 #else
138 XImage *logo;
139 GC backGC;
140 Colormap cmap;
141 int graphics_format;
142 #endif
143 } puzzlestruct;
144
145 static puzzlestruct *puzzles = (puzzlestruct *) NULL;
146
147 static void
free_stuff(Display * display,puzzlestruct * pp)148 free_stuff(Display * display, puzzlestruct * pp)
149 {
150 if (pp->cmap != None) {
151 XFreeColormap(display, pp->cmap);
152 if (pp->backGC != None) {
153 XFreeGC(display, pp->backGC);
154 pp->backGC = None;
155 }
156 pp->cmap = None;
157 } else
158 pp->backGC = None;
159 }
160
161 static void
free_puzzle_screen(Display * display,puzzlestruct * pp)162 free_puzzle_screen(Display * display, puzzlestruct * pp)
163 {
164 if (pp == NULL) {
165 return;
166 }
167 if (pp->fixbuff != NULL) {
168 free(pp->fixbuff);
169 pp->fixbuff = (int *) NULL;
170 }
171 if (pp->bufferBox != None) {
172 XFreePixmap(display, pp->bufferBox);
173 pp->bufferBox = None;
174 }
175 free_stuff(display, pp);
176 #ifndef STANDALONE
177 /* this used to work there I think */
178
179 if (pp->logo != None) {
180 destroyImage(&pp->logo, &pp->graphics_format);
181 pp->logo = None;
182 }
183 #endif
184 pp = NULL;
185 }
186
187 #ifdef NUMBERED
188 extern XFontStruct *getFont(Display * display);
189
190 #define font_height(f) (f->ascent + f->descent)
191 static XFontStruct *mode_font = None;
192
193 static int
font_width(XFontStruct * font,char ch)194 font_width(XFontStruct * font, char ch)
195 {
196 int dummy;
197 XCharStruct xcs;
198
199 (void) XTextExtents(font, &ch, 1, &dummy, &dummy, &dummy, &xcs);
200 return xcs.width;
201 }
202
203 static Bool
NumberScreen(ModeInfo * mi)204 NumberScreen(ModeInfo * mi)
205 {
206 Display *display = MI_DISPLAY(mi);
207 Window window = MI_WINDOW(mi);
208 puzzlestruct *pp = &puzzles[MI_SCREEN(mi)];
209
210 if (mode_font == None)
211 mode_font = getFont(display);
212 if (!pp->done) {
213 XGCValues gcv;
214
215 pp->done = 1;
216 gcv.font = mode_font->fid;
217 gcv.graphics_exposures = False;
218 gcv.foreground = MI_WHITE_PIXEL(mi);
219 gcv.background = MI_BLACK_PIXEL(mi);
220 if ((pp->gc = XCreateGC(display, window,
221 GCForeground | GCBackground | GCGraphicsExposures | GCFont,
222 &gcv)) == None) {
223 free_puzzle_screen(display, pp);
224 return False;
225 }
226 pp->ascent = mode_font->ascent;
227 pp->fontHeight = font_height(mode_font);
228 pp->fontWidth = font_width(mode_font, '5');
229 }
230 XSetForeground(display, pp->gc, MI_WHITE_PIXEL(mi));
231
232 {
233 XPoint pos, letter;
234 int count = 1, digitOffset = 1, temp, letterOffset;
235 int i, j, mult = pp->count.x * pp->count.y;
236 char buf[16];
237
238 letter.x = pp->boxsize.x / 2 - 3;
239 letter.y = pp->boxsize.y / 2 + pp->ascent / 2 - 1;
240 letterOffset = pp->fontWidth / 2;
241 pos.y = 0;
242 for (j = 0; j < pp->count.y; j++) {
243 pos.x = 0;
244 for (i = 0; i < pp->count.x; i++) {
245 if (count < mult) {
246 if (pp->boxsize.x > 2 * pp->fontWidth &&
247 pp->boxsize.y > pp->fontHeight) {
248 (void) sprintf(buf, "%d", count);
249 (void) XDrawString(display, window, pp->gc,
250 pos.x + letter.x - letterOffset * digitOffset +
251 pp->randompos.x,
252 pos.y + letter.y + pp->randompos.y, buf, digitOffset);
253 }
254 XDrawRectangle(display, window, pp->gc,
255 pos.x + 1 + pp->randompos.x, pos.y + 1 + pp->randompos.y,
256 pp->boxsize.x - 3, pp->boxsize.y - 3);
257 count++;
258 digitOffset = 0;
259 temp = count;
260 while (temp >= 1) {
261 temp /= 10;
262 digitOffset++;
263 }
264 }
265 pos.x += pp->boxsize.x;
266 }
267 pos.y += pp->boxsize.y;
268 }
269 }
270 return True;
271 }
272 #endif
273
274 static int
setupmove(ModeInfo * mi)275 setupmove(ModeInfo * mi)
276 {
277 puzzlestruct *pp = &puzzles[MI_SCREEN(mi)];
278
279 if ((pp->prev == pp->excount) && (pp->excount > 0) && (pp->forward == 1)) {
280 pp->lastbox = -1;
281 pp->forward = 0;
282 pp->prev--;
283 } else if ((pp->prev == -1) && (pp->excount > 0) && (pp->forward == 0)) {
284 pp->lastbox = -1;
285 pp->forward = 1;
286 pp->prev++;
287 }
288 if (pp->forward)
289 pp->nextbox = NRAND(5);
290 else
291 pp->nextbox = pp->fixbuff[pp->prev];
292
293 switch (pp->nextbox) {
294 case 0:
295 if ((pp->row == 0) || (pp->lastbox == 2))
296 pp->nextbox = NOWAY;
297 else {
298 pp->nextrow = pp->row - 1;
299 pp->nextcol = pp->col;
300 }
301 break;
302 case 1:
303 if ((pp->col == pp->count.x - 1) || (pp->lastbox == 3))
304 pp->nextbox = NOWAY;
305 else {
306 pp->nextrow = pp->row;
307 pp->nextcol = pp->col + 1;
308 }
309 break;
310 case 2:
311 if ((pp->row == pp->count.y - 1) || (pp->lastbox == 0))
312 pp->nextbox = NOWAY;
313 else {
314 pp->nextrow = pp->row + 1;
315 pp->nextcol = pp->col;
316 }
317 break;
318 case 3:
319 if ((pp->col == 0) || (pp->lastbox == 1))
320 pp->nextbox = NOWAY;
321 else {
322 pp->nextrow = pp->row;
323 pp->nextcol = pp->col - 1;
324 }
325 break;
326 default:
327 pp->nextbox = NOWAY;
328 break;
329 }
330
331 if (pp->nextbox != NOWAY) {
332 pp->lastbox = pp->nextbox;
333 return True;
334 } else
335 return False;
336 }
337
338 static void
setupmovedelta(ModeInfo * mi)339 setupmovedelta(ModeInfo * mi)
340 {
341 Display *display = MI_DISPLAY(mi);
342 puzzlestruct *pp = &puzzles[MI_SCREEN(mi)];
343
344 if (pp->bufferBox != None) {
345 XFreePixmap(display, pp->bufferBox);
346 pp->bufferBox = None;
347 }
348 if ((pp->bufferBox = XCreatePixmap(display, MI_WINDOW(mi),
349 pp->boxsize.x, pp->boxsize.y, MI_DEPTH(mi))) == None) {
350 free_puzzle_screen(display, pp);
351 return;
352 }
353 XCopyArea(MI_DISPLAY(mi), MI_WINDOW(mi), pp->bufferBox, pp->backGC,
354 pp->nextcol * pp->boxsize.x + pp->randompos.x + 1,
355 pp->nextrow * pp->boxsize.y + pp->randompos.y + 1,
356 pp->boxsize.x - 2, pp->boxsize.y - 2, 0, 0);
357 XFlush(MI_DISPLAY(mi));
358
359 if (pp->nextcol > pp->col) {
360 pp->cfactor = -1;
361 pp->cbs = pp->boxsize.x;
362 pp->cbw = pp->incrementOfMove;
363 } else if (pp->col > pp->nextcol) {
364 pp->cfactor = 1;
365 pp->cbs = -pp->incrementOfMove;
366 pp->cbw = pp->incrementOfMove;
367 } else {
368 pp->cfactor = 0;
369 pp->cbs = 0;
370 pp->cbw = pp->boxsize.x;
371 }
372 if (pp->nextrow > pp->row) {
373 pp->rfactor = -1;
374 pp->rbs = pp->boxsize.y;
375 pp->rbw = pp->incrementOfMove;
376 } else if (pp->row > pp->nextrow) {
377 pp->rfactor = 1;
378 pp->rbs = -pp->incrementOfMove;
379 pp->rbw = pp->incrementOfMove;
380 } else {
381 pp->rfactor = 0;
382 pp->rbs = 0;
383 pp->rbw = pp->boxsize.y;
384 }
385
386 if (pp->cfactor == 0)
387 pp->lengthOfMove = pp->boxsize.y;
388 else if (pp->rfactor == 0)
389 pp->lengthOfMove = pp->boxsize.x;
390 else
391 pp->lengthOfMove = MIN(pp->boxsize.x, pp->boxsize.y);
392 pp->Lp = pp->incrementOfMove;
393 }
394
395 static void
wrapupmove(ModeInfo * mi)396 wrapupmove(ModeInfo * mi)
397 {
398 puzzlestruct *pp = &puzzles[MI_SCREEN(mi)];
399
400 if (pp->excount) {
401 if (pp->forward) {
402 pp->fixbuff[pp->prev] = (pp->nextbox + 2) % 4;
403 pp->prev++;
404 } else
405 pp->prev--;
406 }
407 }
408
409 static void
wrapupmovedelta(ModeInfo * mi)410 wrapupmovedelta(ModeInfo * mi)
411 {
412 puzzlestruct *pp = &puzzles[MI_SCREEN(mi)];
413
414 if (pp->bufferBox) {
415
416 XCopyArea(MI_DISPLAY(mi), pp->bufferBox, MI_WINDOW(mi), pp->backGC,
417 0, 0, pp->boxsize.x - 2, pp->boxsize.y - 2,
418 pp->col * pp->boxsize.x + pp->randompos.x + 1,
419 pp->row * pp->boxsize.y + pp->randompos.y + 1);
420
421 XFlush(MI_DISPLAY(mi));
422
423 pp->row = pp->nextrow;
424 pp->col = pp->nextcol;
425
426 XFreePixmap(MI_DISPLAY(mi), pp->bufferBox);
427 pp->bufferBox = None;
428 }
429 }
430
431 static int
moveboxdelta(ModeInfo * mi)432 moveboxdelta(ModeInfo * mi)
433 {
434 puzzlestruct *pp = &puzzles[MI_SCREEN(mi)];
435 int cf = pp->nextcol * pp->boxsize.x +
436 pp->Lp * pp->cfactor + pp->randompos.x;
437 int rf = pp->nextrow * pp->boxsize.y +
438 pp->Lp * pp->rfactor + pp->randompos.y;
439
440 if (pp->Lp <= pp->lengthOfMove) {
441 if (pp->bufferBox) {
442 XCopyArea(MI_DISPLAY(mi), pp->bufferBox, MI_WINDOW(mi),
443 pp->backGC, 0, 0, pp->boxsize.x - 2, pp->boxsize.y - 2,
444 cf + 1, rf + 1);
445 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), pp->backGC,
446 cf + pp->cbs - 1, rf + pp->rbs - 1, pp->cbw + 2, pp->rbw + 2);
447 }
448 if ((pp->Lp + pp->incrementOfMove > pp->lengthOfMove) &&
449 (pp->Lp != pp->lengthOfMove))
450 pp->Lp = pp->lengthOfMove - pp->incrementOfMove;
451 pp->Lp += pp->incrementOfMove;
452 return False;
453 } else
454 return True;
455 }
456
457 static Bool
init_stuff(ModeInfo * mi)458 init_stuff(ModeInfo * mi)
459 {
460 puzzlestruct *pp = &puzzles[MI_SCREEN(mi)];
461 #ifdef STANDALONE
462 #ifdef HAVE_XPM
463 XpmAttributes attrib;
464 attrib.visual = MI_VISUAL(mi);
465 attrib.colormap = MI_COLORMAP(mi);
466 attrib.depth = MI_DEPTH(mi);
467 attrib.valuemask = XpmVisual | XpmColormap | XpmDepth;
468 if (MI_NPIXELS(mi) > 2 &&
469 (XpmSuccess == XpmCreateImageFromData(MI_DISPLAY(mi),
470 PUZZLE_NAME, &(pp->logo), (XImage **) NULL, &attrib))) {
471 pp->graphics_format = IS_XPM;
472 } else
473 #endif
474 {
475
476 int default_width = PUZZLE_WIDTH;
477 int default_height = PUZZLE_HEIGHT;
478 unsigned char * default_bits = PUZZLE_BITS;
479 if (!blogo.data) {
480 blogo.data = (char *) default_bits;
481 blogo.width = default_width;
482 blogo.height = default_height;
483 blogo.bytes_per_line = (blogo.width + 7) / 8;
484 }
485 pp->logo = &blogo;
486 pp->graphics_format = IS_XBM;
487 }
488 #else
489 Display *display = MI_DISPLAY(mi);
490
491 if (pp->logo == None)
492 getImage(mi, &pp->logo, PUZZLE_WIDTH, PUZZLE_HEIGHT, PUZZLE_BITS,
493 #ifdef HAVE_XPM
494 DEFAULT_XPM, PUZZLE_NAME,
495 #endif
496 &pp->graphics_format, &pp->cmap, &pp->black);
497 if (pp->logo == None) {
498 free_puzzle_screen(display, pp);
499 return False;
500 }
501 if (pp->cmap != None) {
502 Window window = MI_WINDOW(mi);
503 setColormap(display, window, pp->cmap, MI_IS_INWINDOW(mi));
504 if (pp->backGC == None) {
505 XGCValues xgcv;
506
507 xgcv.background = pp->black;
508 if ((pp->backGC = XCreateGC(display, window, GCBackground,
509 &xgcv)) == None) {
510 free_puzzle_screen(display, pp);
511 return False;
512 }
513 }
514 } else
515 #endif /* STANDALONE */
516 {
517 pp->black = MI_BLACK_PIXEL(mi);
518 pp->backGC = MI_GC(mi);
519 }
520 return True;
521 }
522
523 ENTRYPOINT void
init_puzzle(ModeInfo * mi)524 init_puzzle(ModeInfo * mi)
525 {
526 Display *display = MI_DISPLAY(mi);
527 Window window = MI_WINDOW(mi);
528 puzzlestruct *pp;
529 int x, y;
530 XPoint size;
531
532 MI_INIT(mi, puzzles);
533 pp = &puzzles[MI_SCREEN(mi)];
534
535 if (pp->painted && pp->windowsize.x == MI_WIDTH(mi) &&
536 pp->windowsize.y == MI_HEIGHT(mi))
537 return; /* Debounce since refresh_puzzle is init_puzzle */
538
539 #ifdef HAVE_XPM
540 if (pp->graphics_format >= IS_XPM) {
541 /* This is needed when another program changes the colormap. */
542 free_puzzle_screen(display, pp);
543 }
544 #endif
545 if (!init_stuff(mi))
546 return;
547 pp->excount = MI_COUNT(mi);
548 if (pp->excount < 0) {
549 if (pp->fixbuff != NULL) {
550 free(pp->fixbuff);
551 pp->fixbuff = (int *) NULL;
552 }
553 pp->excount = NRAND(-pp->excount) + 1;
554 }
555 pp->lastbox = -1;
556 pp->moves = 0;
557 pp->movingBox = False;
558
559 pp->windowsize.x = MI_WIDTH(mi);
560 pp->windowsize.y = MI_HEIGHT(mi);
561 if (pp->windowsize.x < 7)
562 pp->windowsize.x = 7;
563 if (pp->windowsize.y < 7)
564 pp->windowsize.y = 7;
565 pp->forward = 1;
566 pp->prev = 0;
567 /* don't want any exposure events from XCopyArea */
568 XSetGraphicsExposures(display, pp->backGC, False);
569
570 MI_CLEARWINDOWCOLORMAP(mi, pp->backGC, pp->black);
571
572 if (pp->logo == None) {
573 size.x = pp->windowsize.x;
574 size.y = pp->windowsize.y;
575 } else {
576 size.x = (pp->logo->width < pp->windowsize.x) ?
577 pp->logo->width : pp->windowsize.x;
578 size.y = (pp->logo->height < pp->windowsize.y) ?
579 pp->logo->height : pp->windowsize.y;
580 }
581 pp->boxsize.y = NRAND(1 + size.y / 4) + 6;
582 pp->boxsize.x = NRAND(1 + size.x / 4) + 6;
583 if ((pp->boxsize.x > 4 * pp->boxsize.y) ||
584 pp->boxsize.y > 4 * pp->boxsize.x)
585 pp->boxsize.x = pp->boxsize.y = 2 * MIN(pp->boxsize.x, pp->boxsize.y);
586 pp->count.x = size.x / pp->boxsize.x;
587 pp->count.y = size.y / pp->boxsize.y;
588
589 if (pp->bufferBox != None) {
590 XFreePixmap(display, pp->bufferBox);
591 pp->bufferBox = None;
592 }
593 pp->usablewindow.x = pp->count.x * pp->boxsize.x;
594 pp->usablewindow.y = pp->count.y * pp->boxsize.y;
595 pp->offsetwindow.x = (pp->windowsize.x - pp->usablewindow.x) / 2;
596 pp->offsetwindow.y = (pp->windowsize.y - pp->usablewindow.y) / 2;
597
598 pp->incrementOfMove = MIN(pp->usablewindow.x, pp->usablewindow.y) / 20;
599 pp->incrementOfMove = MAX(pp->incrementOfMove, 1);
600
601 if (pp->logo != None) {
602 pp->randompos.x = NRAND(MAX((pp->windowsize.x - pp->logo->width),
603 2 * pp->offsetwindow.x + 1));
604 pp->randompos.y = NRAND(MAX((pp->windowsize.y - pp->logo->height),
605 2 * pp->offsetwindow.y + 1));
606 if (MI_NPIXELS(mi) <= 2)
607 XSetForeground(display, pp->backGC, MI_WHITE_PIXEL(mi));
608 else
609 XSetForeground(display, pp->backGC, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
610 (void) XPutImage(display, window, pp->backGC, pp->logo,
611 (int) (NRAND(MAX(1, (pp->logo->width - pp->usablewindow.x)))),
612 (int) (NRAND(MAX(1, (pp->logo->height - pp->usablewindow.y)))),
613 pp->randompos.x, pp->randompos.y,
614 pp->usablewindow.x, pp->usablewindow.y);
615 XSetForeground(display, pp->backGC, pp->black);
616 for (x = 0; x <= pp->count.x; x++) {
617 int tempx = x * pp->boxsize.x;
618
619 XDrawLine(display, window, pp->backGC,
620 tempx + pp->randompos.x, pp->randompos.y,
621 tempx + pp->randompos.x, pp->usablewindow.y + pp->randompos.y);
622 XDrawLine(display, window, pp->backGC,
623 tempx + pp->randompos.x - 1, pp->randompos.y,
624 tempx + pp->randompos.x - 1, pp->usablewindow.y + pp->randompos.y);
625 }
626 for (y = 0; y <= pp->count.y; y++) {
627 int tempy = y * pp->boxsize.y;
628
629 XDrawLine(display, window, pp->backGC,
630 pp->randompos.x, tempy + pp->randompos.y,
631 pp->usablewindow.x + pp->randompos.x, tempy + pp->randompos.y);
632 XDrawLine(display, window, pp->backGC,
633 pp->randompos.x, tempy + pp->randompos.y - 1,
634 pp->usablewindow.x + pp->randompos.x, tempy + pp->randompos.y - 1);
635 }
636 }
637 #ifdef NUMBERED
638 else {
639 if (pp->image)
640 (void) XDestroyImage(pp->image);
641 pp->randompos.x = pp->offsetwindow.x;
642 pp->randompos.y = pp->offsetwindow.y;
643 if (!NumberScreen(mi)) {
644 release_puzzles(mi);
645 return;
646 }
647 if ((pp->image = XGetImage(display, window,
648 pp->offsetwindow.x, pp->offsetwindow.y,
649 pp->usablewindow.x, pp->usablewindow.y,
650 AllPlanes,
651 (MI_NPIXELS(mi) <= 2) ? XYPixmap : ZPixmap)) == None) {
652 free_puzzle_screen(display, pp);
653 return;
654 }
655 }
656
657 pp->row = pp->count.y - 1;
658 pp->col = pp->count.x - 1;
659 #else
660 pp->row = NRAND(pp->count.y);
661 pp->col = NRAND(pp->count.x);
662 #endif
663
664 if ((pp->excount) && (pp->fixbuff == NULL))
665 if ((pp->fixbuff = (int *) calloc(pp->excount,
666 sizeof (int))) == NULL) {
667 free_puzzle_screen(display, pp);
668 return;
669 }
670 pp->painted = True;
671 }
672
673 ENTRYPOINT void
draw_puzzle(ModeInfo * mi)674 draw_puzzle(ModeInfo * mi)
675 {
676 puzzlestruct *pp;
677
678 if (puzzles == NULL)
679 return;
680 pp = &puzzles[MI_SCREEN(mi)];
681 if (pp->fixbuff == NULL)
682 return;
683
684 MI_IS_DRAWN(mi) = True;
685 pp->painted = False;
686 if (pp->movingBox) {
687 if (moveboxdelta(mi)) {
688 wrapupmovedelta(mi);
689 wrapupmove(mi);
690 pp->movingBox = False;
691 if (pp->moves++ > 2 * MI_COUNT(mi))
692 init_puzzle(mi);
693 }
694 } else {
695 if (setupmove(mi)) {
696 setupmovedelta(mi);
697 pp->movingBox = True;
698 }
699 }
700 }
701
702 ENTRYPOINT void
release_puzzle(ModeInfo * mi)703 release_puzzle(ModeInfo * mi)
704 {
705 if (puzzles != NULL) {
706 int screen;
707
708 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
709 free_puzzle_screen(MI_DISPLAY(mi), &puzzles[screen]);
710 free(puzzles);
711 puzzles = (puzzlestruct *) NULL;
712 }
713 #ifdef NUMBERED
714 if (mode_font != None) {
715 XFreeFont(MI_DISPLAY(mi), mode_font);
716 mode_font = None;
717 }
718 #endif
719 }
720
721 XSCREENSAVER_MODULE ("Puzzle", puzzle)
722
723 #endif /* MODE_puzzle */
724