1 /* $Id: sxsame.c,v 1.1 1996/05/04 19:08:18 yoneyama Exp yoneyama $
2  */
3 /************************************************************************
4  * SameGame for X Window (sxsame)                                       *
5  * Copyleft  (c) 1994-1996  Software Research Academy                   *
6  *  Original idea  Eiji Fukumoto (fukumoto@yh.ntts.co.jp)               *
7  *  Produced by    Y.YONEYAMA                                           *
8  *  Special thanks Tetsu Satoh   (tetu-s@is.aist-nara.ac.jp),           *
9  *                 Yoh Asami     (asami@dv1.nnes.nec.co.jp)             *
10  ************************************************************************/
11 char *program_name    = "SameGame";
12 char *program_version = "3.02";
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <time.h>
18 #include <string.h>
19 #include <sys/param.h>
20 #include <X11/Xlib.h>
21 #include <X11/Xutil.h>
22 #ifndef LOCAL_XPM_H
23 # include <X11/xpm.h>
24 #else /* LOCAL_XPM_H */
25 # include "xpm.h"
26 #endif /* LOCAL_XPM_H */
27 
28 #include "config.h"
29 #include "sxsame.h"
30 
31 #ifdef ENABLE_HISCORE
32 # include "hiscore.h"
33 #endif /* ENABLE_HISCORE */
34 
35 #include "data/sameicon.xpm"
36 
37 char *same_dir = SAME_DIR;
38 extern SameData data_struct[];
39 
40 
41 char     *display = NULL;
42 char     *same_font = NULL;
43 Display  *dpy;
44 Colormap cmap;
45 Window   root;
46 Window     win;
47 Window       same;
48 #define BUTTON_NUM 5
49 Window       button[BUTTON_NUM];
50 Window       scorewin;
51 Window       lastscore;
52 Window         button5;
53 
54 char *button_item[BUTTON_NUM] = {
55 	"Quit", "NewGame", "Undo", "Size", "Pictures"
56 };
57 struct {
58 	int x;
59 	int y;
60 	int width;
61 	int height;
62 	int lock;
63 } button_struct[BUTTON_NUM];
64 
65 int size_small(
66 #if NeedFunctionPrototypes
67 void
68 #endif
69 );
70 int size_normal(
71 #if NeedFunctionPrototypes
72 void
73 #endif
74 );
75 int size_large(
76 #if NeedFunctionPrototypes
77 void
78 #endif
79 );
80 int size_huge(
81 #if NeedFunctionPrototypes
82 void
83 #endif
84 );
85 int pic_marble(
86 #if NeedFunctionPrototypes
87 void
88 #endif
89 );
90 int pic_head(
91 #if NeedFunctionPrototypes
92 void
93 #endif
94 );
95 int pic_face(
96 #if NeedFunctionPrototypes
97 void
98 #endif
99 );
100 int pic_other(
101 #if NeedFunctionPrototypes
102 void
103 #endif
104 );
105 
106 struct item_struct size_item[] = {
107 /*        string   lock  function  */
108 	{ "Small"  , 0, size_small },
109 	{ "Normal" , 0, size_normal},
110 	{ "Large"  , 0, size_large },
111 	{ "Huge"   , 0, size_huge  },
112 	{ 0        , 0, 0          }
113 };
114 struct item_struct pictures_item[] = {
115 	{ "Marble" , 0, pic_marble },
116 	{ "Head"   , 0, pic_head   },
117 	{ "Face"   , 0, pic_face   },
118 	{ ""       , 0, 0          },
119 	{ "(other)", 1, pic_other  },
120 	{ 0        , 0, 0          }
121 };
122 
123 
124 
125 #define SXS_MAX_X 30
126 #define SXS_MAX_Y 20
127 
128 
129 SameGame game;
130 DataFile **datafiles;
131 int      ndatafile;
132 
133 GC       gc;
134 Font     font;
135 int      char_width;
136 int      char_height = 14;
137 
138 XpmAttributes xpm_attr;
139 
140 int      bits[MAX_WIDTH][MAX_HEIGHT];
141 int      sbits[MAX_WIDTH][MAX_HEIGHT];
142 int      save_bits[MAX_WIDTH][MAX_HEIGHT];
143 
144 unsigned long black, white, gray;
145 unsigned int box_color;
146 
147 /* Frame data of B&W BMP */
148 #define bwf_x 8
149 #define bwf_y 8
150 static char bwf_bits[] = {
151    0xd5, 0xaa, 0xd5, 0xaa, 0xd5, 0xaa, 0xd5, 0xff};
152 
153 
154 int      score;
155 int      rest;
156 int      same_size = -1;
157 int      same_width, same_height;
158 int      same_pic  = 1;
159 int      game_over;
160 int      entry_score;
161 int      hi_num = 5;
162 int	 same_other_pic = 0;
163 
164 int      hisc_width = 176;
165 #ifdef ENABLE_HISCORE
166 int      hisc_height = 128;
167 #else  /* !ENABLE_HISCORE */
168 int      hisc_height = 80;
169 #endif /* !ENABLE_HISCORE */
170 
171 int ReadInitFile(int* width, int* height, int* same_pic);
172 int SaveInitFile(int width, int height, int same_pic);
173 int CheckSameDataFile(DataFile ***);
174 int LoadBMPSameData(Display *dpy, Colormap cmap, SameGame *, char *);
175 int LoadSameData(ImportSameData *, char *);
176 int CheckSelectSame(int sx, int sy);
177 
178 static
179 int
Access(const char * path)180 Access(const char* path)
181 {
182 	return access(path, R_OK);
183 }
184 
185 # define access(x)	Access(x)
186 
main(argc,argv)187 void main(argc, argv)
188 int argc;
189 char **argv;
190 {
191 	int i;
192 	char *prg_name;
193 
194 	/* get my name */
195 	if((prg_name = (char *)strrchr(argv[0], '/'))!=0)
196 		prg_name++;
197 	else
198 		prg_name = argv[0];
199 
200 	for(i=1;i<argc;i++)
201 	{
202 		if(strcmp(argv[i], "-display")==NULL)
203 		{
204 			if(++i < argc)
205 			{
206 				display = argv[i];
207 				continue;
208 			}
209 		}
210 		printf("%s version %s\n", program_name, program_version);
211 		printf("Usage: %s [-display ???:?.?]\n", prg_name);
212 		exit(0);
213 	}
214 
215 	ReadInitFile(&same_width, &same_height, &same_pic);
216 	sxs();
217 	if(same_pic == -1)
218 		SaveInitFile(same_width, same_height,
219 			BUILTIN_NDATA + same_other_pic);
220 	else
221 		SaveInitFile(same_width, same_height, same_pic);
222 
223 	exit(0);
224 }
225 
226 #define PUSH_BUTTON_MASK (ButtonPressMask | EnterWindowMask \
227 		 | LeaveWindowMask | ExposureMask | ButtonMotionMask)
228 
sxs()229 int sxs()
230 {
231 	XSetWindowAttributes att;
232 	XEvent e;
233 	Window dmyw;
234 	XSizeHints sh;
235 	XWMHints wh;
236 	Pixmap same_icon;
237 	XFontStruct *fs;
238 
239 	int win_width;
240 	int win_height;
241 
242 	int button_pos;
243 
244 	int bd_top = 24;
245 	int bd_bottom = 24;
246 	int bd_left = 16;
247 	int bd_right = 16;
248 
249 	int press_flag;
250 	int undo_flag;
251 	int himap_flag;
252 	int undo_score = 0;
253 	int undo_rest  = 0;
254 
255 	int i, j;
256 	int sx, sy, old_sx, old_sy;
257 	int rx, ry, mx, my, mask;
258 	int sel;
259 
260 	dpy = XOpenDisplay(display);
261 	if(dpy == NULL)
262 	{
263 		fprintf(stderr, "%s: can't open display: %s.\n", program_name,
264 			!display ? ":0.0" : display);
265 		return(0);
266 	}
267 	root = RootWindow(dpy, 0);
268 
269 	cmap = DefaultColormap(dpy, 0);
270 /*
271 *	cmap = XCreateColormap(dpy, root, DefaultVisual(dpy, 0), AllocNone);
272 *	XInstallColormap(dpy, cmap);
273 */
274 
275 /*	font = XLoadFont(dpy, "r14");*/
276 	font = XLoadFont(dpy, MENU_FONT);
277 	fs = XQueryFont(dpy, font);
278 	char_width = XTextWidth(fs, "M", 1);
279 
280 	black = GetColor("black");
281 	white = GetColor("white");
282 	gray = GetColor("gray");
283 
284 	if((ndatafile = CheckSameDataFile(&datafiles)) != 0)
285 		pictures_item[4].lock = 0;
286 
287 	if(same_pic >= BUILTIN_NDATA)
288 	{
289 		same_other_pic = same_pic - BUILTIN_NDATA;
290 		if(same_other_pic >= ndatafile)
291 		{
292 			fprintf(stderr,"Warning: unknown data file.\n");
293 			same_other_pic = -1;
294 		}
295 		same_pic = 1;
296 	}
297 	else
298 		same_other_pic = -1;
299 
300 	game.bit_width  = data_struct[same_pic].width;
301 	game.bit_height = data_struct[same_pic].height;
302 
303 	win_width  = game.bit_width*same_width + bd_left + bd_right;
304 	win_height = game.bit_height*same_height+ bd_top + bd_bottom;
305 	win = XCreateSimpleWindow(dpy, root, 0, 0,
306 			win_width, win_height, 1, black, white);
307 	XSelectInput(dpy, win, ButtonPressMask);
308 
309 	same = XCreateSimpleWindow(dpy, win, bd_left, bd_top,
310 			game.bit_width*same_width, game.bit_height*same_height,
311 			0, black, white);
312 	XSelectInput(dpy, same, ExposureMask | ButtonPressMask |
313 				ButtonReleaseMask | PointerMotionMask |
314 				EnterWindowMask | LeaveWindowMask);
315 	att.win_gravity = NorthWestGravity;
316 	XChangeWindowAttributes(dpy, same, CWWinGravity, &att);
317 
318 	for(button_pos=0, i=0;i<BUTTON_NUM;i++)
319 	{
320 		button_struct[i].x = bd_left + button_pos;
321 		button_struct[i].y = 4;
322 		button_struct[i].width = char_width*
323 					(strlen(button_item[i])+1);
324 		button_struct[i].height = 14;
325 		button_struct[i].lock = 0;
326 		button[i] = XCreateSimpleWindow(dpy, win, button_struct[i].x,
327 			button_struct[i].y, button_struct[i].width,
328 			button_struct[i].height, 1, black, white);
329 		button_pos += char_width*(strlen(button_item[i])+2);
330 		XSelectInput(dpy, button[i], ButtonPressMask |
331 				EnterWindowMask | LeaveWindowMask |
332 				ExposureMask | ButtonMotionMask);
333 		att.win_gravity = NorthWestGravity;
334 		XChangeWindowAttributes(dpy, button[i], CWWinGravity, &att);
335 	}
336 
337 	scorewin = XCreateSimpleWindow(dpy, win, bd_left,
338 			game.bit_height*same_height + bd_top + 4, 272, 14,
339 			1, black, white);
340 	XSelectInput(dpy, scorewin, ButtonPressMask | ExposureMask);
341 	att.win_gravity = SouthWestGravity;
342 	XChangeWindowAttributes(dpy, scorewin, CWWinGravity, &att);
343 
344 	lastscore = XCreateSimpleWindow(dpy, win, (win_width - hisc_width)/2,
345 				38, hisc_width, hisc_height, 8, black, white);
346 	XSelectInput(dpy, lastscore, ExposureMask);
347 	att.win_gravity = NorthGravity;
348 	XChangeWindowAttributes(dpy, lastscore, CWWinGravity, &att);
349 
350 	button5 = XCreateSimpleWindow(dpy, lastscore, (hisc_width - 64)/2,
351 				hisc_height - 24, 64, 14, 1, black, white);
352 	XSelectInput(dpy, button5, ButtonPressMask | EnterWindowMask |
353 				LeaveWindowMask);
354 	att.win_gravity = SouthWestGravity;
355 	XChangeWindowAttributes(dpy, button5, CWWinGravity, &att);
356 
357 	XMapWindow(dpy, win);
358 	XMapWindow(dpy, same);
359 	for(i=0;i<BUTTON_NUM;i++)
360 		XMapWindow(dpy, button[i]);
361 	XMapWindow(dpy, scorewin);
362 
363 	XStoreName(dpy, win, program_name);
364 
365 	gc = XCreateGC(dpy, same, 0, 0);
366 
367 	/*xpm_attr.colormap = DefaultColormap(dpy, 0);*/
368 	xpm_attr.colormap = cmap;
369 	xpm_attr.valuemask = XpmSize | XpmReturnPixels | XpmColormap;
370 	/*xpm_attr.valuemask = XpmReturnPixels | XpmColormap;*/
371 
372 	if(XpmCreatePixmapFromData(dpy, root, sameicon_xpm, &same_icon,
373 				NULL, &xpm_attr) != XpmSuccess)
374 	{
375 		fprintf(stderr,"Error: can't create pixmap from data.\n");
376 		return(0);
377 	}
378 	wh.icon_pixmap = same_icon;
379 	wh.flags = IconPixmapHint;
380 	XSetWMHints(dpy, win, &wh);
381 
382 picture_game:
383 
384 	if(same_other_pic != -1) same_pic = -1;
385 	if(same_pic >= 0 && same_pic <= BUILTIN_NDATA)
386 	{
387 		if(CreateData(&data_struct[same_pic])==-1)
388 			CreateData(&data_struct[1]);
389 	}
390 	else
391 	{
392 		if(CreateDataFromFile(datafiles[same_other_pic]->fname) == -1)
393 		{
394 			datafiles[same_other_pic]->lock = 1;
395 			same_pic = 1;
396 			CreateData(&data_struct[1]);
397 		}
398 	}
399 
400 resize_game:
401 
402 	if(same_width == 15 && same_height == 8)
403 		same_size = 0;
404 	else if(same_width == 20 && same_height == 10)
405 		same_size = 1;
406 	else if(same_width == 25 && same_height == 15)
407 		same_size = 2;
408 	else if(same_width == 30 && same_height == 20)
409 		same_size = 3;
410 	else
411 		same_size = -1;
412 
413 	XSetWindowBackgroundPixmap(dpy, win, game.frame_xpm);
414 	XClearWindow(dpy, win);
415 	XSetWindowBackgroundPixmap(dpy, same, game.bg_xpm);
416 	XClearWindow(dpy, same);
417 	XSetWindowBorderPixmap(dpy, lastscore, game.frame_xpm);
418 
419 	sh.min_width  = game.bit_width*same_width + bd_left + bd_right;
420 	sh.min_height = game.bit_height*same_height+ bd_top + bd_bottom;
421 	sh.max_width  = sh.min_width;
422 	sh.max_height = sh.min_height;
423 	sh.flags = PMinSize | PMaxSize;
424 	XSetNormalHints(dpy, win, &sh);
425 
426 	win_width  = game.bit_width*same_width + bd_left + bd_right;
427 	win_height = game.bit_height*same_height+ bd_top + bd_bottom;
428 	XResizeWindow(dpy, win, win_width, win_height);
429 	XResizeWindow(dpy, same, game.bit_width*same_width,
430 						game.bit_height*same_height);
431 
432 #ifdef ENABLE_HISCORE
433 	if(win_height > 250)
434 	{
435 		hi_num = 10;
436 		hisc_height = 208;
437 	}
438 	else
439 	{
440 		hi_num = 5;
441 		hisc_height = 128;
442 	}
443 	XResizeWindow(dpy, lastscore, hisc_width, hisc_height);
444 #endif /* ENABLE_HISCORE*/
445 	XFlush(dpy);
446 
447 new_game:
448 
449 	/* Initialize */
450 	srand((int)time((time_t *)NULL));
451 	for(i=0;i<same_width;i++)
452 	{
453 		for(j=0;j<same_height;j++)
454 		{
455 			bits[i][j] = (rand()/3)%5+1;
456 			sbits[i][j] = 0;
457 		}
458 	}
459 	score = 0;
460 	entry_score = 0;
461 	rest = same_width*same_height;
462 
463 	for(i=0;i<BUTTON_NUM;i++)
464 		DrawButton(i);
465 
466 undo_game:
467 
468 	XUnmapSubwindows(dpy, lastscore);
469 	XUnmapWindow(dpy, lastscore);
470 	himap_flag = 0;
471 	game_over = 0;
472 
473 	DrawAllBits(same_width, same_height, 0);
474 	undo_flag = 0;
475 	button_struct[2].lock = 1;
476 	DrawButton(2);
477 	DrawScore();
478 	memcpy(save_bits, bits, sizeof(save_bits));
479 	press_flag = 0;
480 
481 	old_sx = old_sy = sx = sy = -1;
482 	while(1)
483 	{
484 
485 main_loop:
486 		if(ScanSame(same_width, same_height) == 0 && game_over == 0)
487 		/* check game over */
488 		{
489 			game_over = 1;
490 			DrawAllBits(same_width, same_height, 2);
491 			XMapWindow(dpy, lastscore);
492 			XMapSubwindows(dpy, lastscore);
493 			undo_flag = 0;
494 			button_struct[2].lock = 1;
495 			himap_flag = 1;
496 			DrawButton(2);
497 		}
498 		if(sx >= 0 && sy >= 0 && (sx != old_sx || sy != old_sy)
499 			&& sbits[sx][sy] == 0)
500 		{
501 			DrawSameRect(same_width, same_height, sx, sy);
502 		}
503 		old_sx = sx;
504 		old_sy = sy;
505 		XNextEvent(dpy, &e);
506 		switch(e.type)
507 		{
508 		case Expose:
509 			if(e.xany.window == same)
510 			{
511 				while(XCheckWindowEvent(dpy, same,
512 					ExposureMask, &e)==True);
513 				if(game_over)
514 					DrawAllBits(same_width, same_height, 2);
515 				else
516 					DrawAllBits(same_width, same_height, 0);
517 				break;
518 			}
519 			if(e.xany.window == lastscore)
520 			{
521 				DrawLastScore();
522 				DrawLastScoreButton();
523 				break;
524 			}
525 			if(e.xany.window == scorewin)
526 			{
527 				DrawScore();
528 				break;
529 			}
530 			for(i=0;i<BUTTON_NUM;i++)
531 			{
532 				if(e.xany.window == button[i])
533 				{
534 					DrawButton(i);
535 					goto main_loop;
536 				}
537 			}
538 			break;
539 		case ButtonPress:
540 			if(e.xbutton.button == 3) return(0);/* right button */
541 			if(e.xany.window == button[0])
542 				goto quit_game;
543 			if(e.xany.window == button[1])
544 				goto new_game;
545 			if(e.xany.window == button5)
546 			{
547 				if(game_over == 1)
548 					goto new_game;
549 				else
550 				{
551 					XUnmapSubwindows(dpy, lastscore);
552 					XUnmapWindow(dpy, lastscore);
553 					himap_flag = 0;
554 					continue;
555 				}
556 			}
557 			if(e.xany.window == button[2])
558 			{
559 				if(undo_flag == 0 || game_over == 1)
560 					goto main_loop;
561 				memcpy(bits, save_bits, sizeof(bits));
562 				score = undo_score;
563 				rest = undo_rest;
564 				goto undo_game;
565 			}
566 			if(e.xany.window == button[3])
567 			{
568 				EnterButton(3);
569 				sel = SelectMenu(size_item, 3, same_size);
570 				if(sel != -1)
571 					goto resize_game;
572 				old_sx = old_sy = -1;
573 				DrawButton(3);
574 				goto main_loop;
575 			}
576 			if(e.xany.window == button[4])
577 			{
578 				EnterButton(4);
579 				sel = SelectMenu(pictures_item, 4, same_pic);
580 				if(sel != -1)
581 				{
582 					FreeData();
583 					goto picture_game;
584 				}
585 				old_sx = old_sy = -1;
586 				DrawButton(4);
587 				goto main_loop;
588 			}
589 			if(e.xany.window == scorewin)
590 			{
591 				if(himap_flag)
592 				{
593 					XUnmapSubwindows(dpy, lastscore);
594 					XUnmapWindow(dpy, lastscore);
595 					himap_flag = 0;
596 				}
597 				else
598 				{
599 					XMapWindow(dpy, lastscore);
600 					XMapSubwindows(dpy, lastscore);
601 					himap_flag = 1;
602 				}
603 			}
604 			if(e.xany.window == same)
605 			{
606 				DrawSameBits(same_width, same_height, 2);
607 				press_flag = 1;
608 				if(game.bit_pat[2] == 0) goto delete_same;
609 			}
610 			break;
611 		case ButtonRelease:
612 			if(e.xany.window == same && press_flag == 1 &&
613 				game_over == 0)
614 			{
615 delete_same:
616 				if(CheckSelectSame(same_width, same_height))
617 				{
618 					memcpy(save_bits, bits,
619 						sizeof(save_bits));
620 					undo_score = score;
621 					undo_rest = rest;
622 					undo_flag = 1;
623 					button_struct[2].lock = 0;
624 					DrawButton(2);
625 					DeleteSame(same_width, same_height);
626 					old_sx = old_sy = -1;
627 					DrawScore();
628 				}
629 				press_flag = 0;
630 				break;
631 			}
632 			break;
633 		case EnterNotify:
634 			for(i=0;i<BUTTON_NUM;i++)
635 			{
636 				if(e.xany.window == button[i])
637 				{
638 					EnterButton(i);
639 					goto main_loop;
640 				}
641 			}
642 			if(e.xany.window == button5)
643 			{
644 				XSetForeground(dpy, gc, black);
645 				XDrawRectangle(dpy, button5, gc, 0, 0, 64-1,
646 						14-1);
647 				break;
648 			}
649 
650 		case MotionNotify:
651 			if(press_flag == 0)
652 			{
653 				XQueryPointer(dpy, same, &dmyw, &dmyw, &rx,
654 						&ry, &mx, &my, &mask);
655 				if(mx >= 0)
656 					sx = mx / game.bit_width;
657 				else
658 					sx = -1;
659 				if(my >= 0)
660 					sy = my / game.bit_height;
661 				else
662 					sy = -1;
663 			}
664 			break;
665 		case LeaveNotify:
666 			for(i=0;i<BUTTON_NUM;i++)
667 			{
668 				if(e.xany.window == button[i])
669 				{
670 					DrawButton(i);
671 					break;
672 				}
673 			}
674 			if(e.xany.window == button5)
675 			{
676 				DrawLastScoreButton();
677 				break;
678 			}
679 			EraseSameRect(same_width, same_height);
680 			old_sx = old_sy = sx = sy = -1;
681 			press_flag = 0;
682 			break;
683 		}
684 
685 		XFlush(dpy);
686 	}
687 
688 quit_game:
689 
690 	return(0);
691 }
692 
CreateData(data)693 int CreateData(data)
694 SameData *data;
695 {
696 	int i, j, val;
697 
698 	game.bit_box = data->box;
699 	game.bit_pat[0] = 1;
700 	game.bit_pat[1] = data->selected;
701 	game.bit_pat[2] = data->pushed;
702 	game.bit_width  = data->width;
703 	game.bit_height = data->height;
704 	if(game.bit_box)
705 	{
706 		if((box_color = GetColor(data->box_color)) == 0)
707 			box_color = white;
708 	}
709 
710 	for(i=0;i<3;i++)
711 	{
712 		for(j=0;j<5;j++)
713 		{
714 			if(data->xpm_data[i][j] != 0)
715 			{
716 				val = XpmCreatePixmapFromData(dpy, root,
717 					data->xpm_data[i][j],
718 					&game.bits_xpm[i][j], NULL, &xpm_attr);
719 				if(val != XpmSuccess) goto error_return;
720 			}
721 			else
722 				game.bits_xpm[i][j] = 0;
723 		}
724 	}
725 	val = XpmCreatePixmapFromData(dpy, root,
726 			data->bg_data,
727 			&game.bg_xpm, NULL, &xpm_attr);
728 	if(val != XpmSuccess) goto error_return;
729 	val = XpmCreatePixmapFromData(dpy, root,
730 			data->frame_data,
731 			&game.frame_xpm, NULL, &xpm_attr);
732 	if(val != XpmSuccess) goto error_return;
733 	return(0);
734 error_return:
735 	fprintf(stderr,"Error: can't create pixmap from data.\n");
736 	return(-1);
737 }
738 
CreateDataFromFile(fname)739 int CreateDataFromFile(fname)
740 char *fname;
741 {
742 	ImportSameData data;
743 	int i, j, val, ncol;
744 	char tmpfname[MAXPATHLEN];
745 
746 	if(strlen(fname)>4) /* check Windows data file... */
747 	{
748 		if(strcmp(&fname[strlen(fname)-4],".bmp") == 0 ||
749 		   strcmp(&fname[strlen(fname)-4],".BMP") == 0)
750 		{
751 			if((ncol = LoadBMPSameData(dpy, cmap, &game, fname))
752 				== -1)
753 				goto error_return;
754 			if(ncol == 2) /* B&W BMP */
755 			{
756 				game.frame_xpm =
757 					XCreatePixmapFromBitmapData(dpy, root,
758 					bwf_bits, bwf_x, bwf_y, black, white,
759 					DefaultDepth(dpy, 0));
760 			}
761 			else
762 			{
763 				val = XpmCreatePixmapFromData(dpy, root,
764 					data_struct[0].frame_data,
765 					&game.frame_xpm, NULL, &xpm_attr);
766 				if(val != XpmSuccess)
767 				{
768 					game.frame_xpm =
769 					  XCreatePixmapFromBitmapData(dpy, root,
770 					  bwf_bits, bwf_x, bwf_y, black, white,
771 					  DefaultDepth(dpy, 0));
772 				}
773 			}
774 			return(0);
775 		}
776 	}
777 
778 	if(LoadSameData(&data, fname) == -1)
779 		goto error_return;
780 
781 	game.bit_box = data.box;
782 	game.bit_pat[0] = 1;
783 	game.bit_pat[1] = data.selected;
784 	game.bit_pat[2] = data.pushed;
785 	game.bit_width  = data.width;
786 	game.bit_height = data.height;
787 	if(game.bit_box)
788 	{
789 		if((box_color = GetColor(data.box_color)) == 0)
790 			box_color = white;
791 		free(data.box_color);
792 	}
793 
794 	for(i=0;i<3;i++)
795 	{
796 		for(j=0;j<5;j++)
797 		{
798 			if(game.bit_pat[i])
799 			{
800 				if(!access(data.xpm_data[i][j]))
801 					strcpy(tmpfname,data.xpm_data[i][j]);
802 				else {
803 					if (MAXPATHLEN <=
804 						snprintf(tmpfname, MAXPATHLEN, "%s/%s",same_dir,
805 						data.xpm_data[i][j])) {
806 						goto xpm_error;
807 					}
808 				}
809 				val = XpmReadFileToPixmap(dpy, root,
810 					tmpfname, &game.bits_xpm[i][j],
811 					NULL, &xpm_attr);
812 				free(data.xpm_data[i][j]);
813 				if(val != XpmSuccess)
814 					goto xpm_error;
815 			}
816 			else
817 			{
818 				game.bits_xpm[i][j] = 0;
819 			}
820 		}
821 	}
822 
823 	if(!access(data.bg_data))
824 		strcpy(tmpfname,data.bg_data);
825 	else
826 		if (MAXPATHLEN <= snprintf(tmpfname, MAXPATHLEN, "%s/%s",same_dir, data.bg_data)) {
827 			goto xpm_error;
828 		}
829 	val = XpmReadFileToPixmap(dpy, root, tmpfname,
830 			&game.bg_xpm, NULL, &xpm_attr);
831 	free(data.bg_data);
832 	if(val != XpmSuccess)
833 		goto xpm_error;
834 
835 	if(!access(data.frame_data))
836 		strcpy(tmpfname,data.frame_data);
837 	else
838 		sprintf(tmpfname,"%s/%s",same_dir, data.frame_data);
839 		if (MAXPATHLEN <= snprintf(tmpfname, MAXPATHLEN, "%s/%s",same_dir, data.frame_data)) {
840 
841 			goto xpm_error;
842 		}
843 	val = XpmReadFileToPixmap(dpy, root, tmpfname,
844 			&game.frame_xpm, NULL, &xpm_attr);
845 	free(data.frame_data);
846 	if(val != XpmSuccess)
847 		goto xpm_error;
848 
849 	return(0);
850 xpm_error:
851 	fprintf(stderr,"Error: can't create pixmap from '%s'.\n", tmpfname);
852 error_return:
853 	return(-1);
854 }
855 
856 
FreeData()857 void FreeData()
858 {
859 	int i,j;
860 	for(i=0;i<3;i++)
861 		for(j=0;j<5;j++)
862 			if(game.bits_xpm[i][j] != 0 && game.bit_pat[i])
863 				XFreePixmap(dpy, game.bits_xpm[i][j]);
864 	XFreePixmap(dpy, game.bg_xpm);
865 	XFreePixmap(dpy, game.frame_xpm);
866 
867 /*
868 *	XUninstallColormap(dpy, cmap);
869 *	XFreeColormap(dpy, cmap);
870 *	cmap = XCreateColormap(dpy, root, DefaultVisual(dpy, 0), AllocNone);
871 *	XInstallColormap(dpy, cmap);
872 *	black = GetColor("black");
873 *	white = GetColor("white");
874 *	gray = GetColor("gray");
875 *	xpm_attr.colormap = cmap;
876 */
877 }
878 
DrawButton(b)879 int DrawButton(b)
880 int b;
881 {
882 	XSetFont(dpy, gc, font);
883 	if(button_struct[b].lock)
884 		XSetForeground(dpy, gc, gray);
885 	else
886 		XSetForeground(dpy, gc, black);
887 	XSetBackground(dpy, gc, white);
888 	XClearWindow(dpy, button[b]);
889 	XDrawImageString(dpy, button[b], gc, 2, 12, button_item[b],
890 		strlen(button_item[b]));
891 	XSetFillStyle(dpy, gc, FillSolid);
892 	return(0);
893 }
894 
EnterButton(b)895 int EnterButton(b)
896 int b;
897 {
898 	if(!button_struct[b].lock)
899 	{
900 		XSetForeground(dpy, gc, black);
901 		XDrawRectangle(dpy, button[b], gc, 0, 0,
902 			button_struct[b].width-1, button_struct[b].height-1);
903 	}
904 	return(0);
905 }
906 
DrawScore()907 int DrawScore()
908 {
909 	char tmp[256];
910 	XSetFont(dpy, gc, font);
911 	XSetForeground(dpy, gc, black);
912 	XSetBackground(dpy, gc, white);
913 	sprintf(tmp, "Gets%6d  Rests%6d  Total%7d", score, rest, score - rest);
914 	XDrawImageString(dpy, scorewin, gc, 2, 12, tmp, strlen(tmp));
915 	return(0);
916 }
917 
DrawLastScore()918 int DrawLastScore()
919 {
920 #ifdef ENABLE_HISCORE
921 	struct Hiscore hiscore;
922 	int i;
923 	int my = 10;
924 	static int failent = 0;
925 #endif /* ENABLE_HISCORE */
926 	char tmp[256];
927 	XSetFont(dpy, gc, font);
928 	XSetForeground(dpy, gc, black);
929 	XSetBackground(dpy, gc, white);
930 	XClearWindow(dpy, lastscore);
931 #ifdef ENABLE_HISCORE
932 	if(game_over == 1 && entry_score == 0 && same_size != -1)
933 	{
934 		entry_score = 1;
935 		my = EntryHiscore(score - rest, same_size, entry_score);
936 		if(my == -1) failent = 1;
937 		else failent = 0;
938 	}
939 	if(game_over == 0)
940 		failent = 0;
941 
942 	if(my != -1 && same_size != -1 && GetHiscore(&hiscore, same_size) != -1
943 		&& failent == 0)
944 	{
945 		XResizeWindow(dpy, lastscore, hisc_width, hisc_height);
946 		XDrawString(dpy, lastscore, gc, 16, 14,
947 				"*** High Score ***", 18);
948 		for(i=0;i<hi_num;i++)
949 		{
950 			if(i == my)
951 				sprintf(tmp, ">%2d. %s", i+1,
952 					hiscore.entry[i].name);
953 			else
954 				sprintf(tmp, " %2d. %s", i+1,
955 					hiscore.entry[i].name);
956 			XDrawString(dpy, lastscore, gc, 8,16*i+30,
957 				tmp, strlen(tmp));
958 			sprintf(tmp, "%6d", hiscore.entry[i].score);
959 			XDrawString(dpy, lastscore, gc, 116, 16*i+30,
960 				tmp, strlen(tmp));
961 		}
962 		return(0);
963 	}
964 	XResizeWindow(dpy, lastscore, 160, 80);
965 #endif  /* ENABLE_HISCORE */
966 	sprintf(tmp, "Gets    %6d", score);
967 	XDrawString(dpy, lastscore, gc, 24, 16, tmp, strlen(tmp));
968 	sprintf(tmp, "Rests   %6d", -rest);
969 	XDrawString(dpy, lastscore, gc, 24, 32, tmp, strlen(tmp));
970 	XDrawLine(dpy, lastscore, gc, 16, 34, 131, 34);
971 	sprintf(tmp, "Total   %6d", score - rest);
972 	XDrawString(dpy, lastscore, gc, 24, 48, tmp, strlen(tmp));
973 	return(0);
974 }
975 
DrawLastScoreButton()976 int DrawLastScoreButton()
977 {
978 	XSetFont(dpy, gc, font);
979 	XSetForeground(dpy, gc, black);
980 	XClearWindow(dpy, button5);
981 	if(game_over == 0)
982 		XDrawString(dpy, button5, gc, 2, 12, "Continue", 8);
983 	else
984 		XDrawString(dpy, button5, gc, 2, 12, "New Game", 8);
985 	return(0);
986 }
987 
DrawAllBits(x,y,pat)988 int DrawAllBits(x, y, pat)
989 int x;
990 int y;
991 int pat;
992 {
993 	int i, j;
994 
995 	for(i=0;i<x;i++)
996 	{
997 		for(j=0;j<y;j++)
998 		{
999 			DrawBit(i, j, pat);
1000 			sbits[i][j] = 0;
1001 		}
1002 	}
1003 	return(0);
1004 }
1005 
DrawBit(sx,sy,pat)1006 int DrawBit(sx, sy, pat)
1007 int sx;
1008 int sy;
1009 int pat;
1010 {
1011 	if(game.bit_pat[pat] == 0) pat = 0;
1012 
1013 	if(bits[sx][sy] == 0)
1014 		XClearArea(dpy, same, sx*game.bit_width, sy*game.bit_height,
1015 			game.bit_width, game.bit_height, False);
1016 	else
1017 		XCopyArea(dpy, game.bits_xpm[pat][bits[sx][sy]-1], same, gc,
1018 			0, 0, game.bit_width, game.bit_height,
1019 			sx*game.bit_width, sy*game.bit_height);
1020 	return(0);
1021 }
1022 
DrawSameBits(x,y,pat)1023 int DrawSameBits(x, y, pat)
1024 int x;
1025 int y;
1026 int pat;
1027 {
1028 	int i, j;
1029 	for(i=0;i<x;i++)
1030 		for(j=0;j<y;j++)
1031 			if(sbits[i][j] == 1)
1032 				DrawBit(i, j, pat);
1033 	return(0);
1034 }
1035 
DrawRect(sx,sy)1036 int DrawRect(sx, sy)
1037 int sx;
1038 int sy;
1039 {
1040 	DrawBit(sx, sy, 1);
1041 	if(game.bit_box)
1042 	{
1043 		XSetForeground(dpy, gc, box_color);
1044 		XDrawRectangle(dpy, same, gc, sx*game.bit_width,
1045 			sy*game.bit_height, game.bit_width - 1,
1046 			game.bit_height - 1);
1047 	}
1048 	return(0);
1049 }
1050 
EraseSameRect(x,y)1051 int EraseSameRect(x, y)
1052 int x;
1053 int y;
1054 {
1055 	int i, j;
1056 
1057 	for(i=0;i<x;i++)
1058 	{
1059 		for(j=0;j<y;j++)
1060 		{
1061 			if(sbits[i][j] == 1)
1062 			{
1063 				sbits[i][j] = 0;
1064 				DrawBit(i, j, 0);
1065 			}
1066 		}
1067 	}
1068 	return(0);
1069 }
1070 
ScanSame(x,y)1071 int ScanSame(x, y)
1072 int x;
1073 int y;
1074 {
1075 	int i, j;
1076 
1077 	for(i=0;i<x;i++)
1078 	{
1079 		if(bits[i][y-1] == 0) break;
1080 		for(j=y-1;j>=0;j--)
1081 		{
1082 			if(bits[i][j] == 0) break;
1083 			if(CheckSame(x, y, i, j)==1) return(1);
1084 		}
1085 	}
1086 	return(0);
1087 }
1088 
1089 
CheckSame(x,y,sx,sy)1090 int CheckSame(x, y, sx, sy)
1091 int x;
1092 int y;
1093 int sx;
1094 int sy;
1095 {
1096 	if(bits[sx][sy] == 0) return(0);
1097 	if(sx>0)
1098 		if(bits[sx][sy] == bits[sx-1][sy])
1099 			return(1);
1100 	if(sx<x-1)
1101 		if(bits[sx][sy] == bits[sx+1][sy])
1102 			return(1);
1103 	if(sy>0)
1104 		if(bits[sx][sy] == bits[sx][sy-1])
1105 			return(1);
1106 	if(sy<y-1)
1107 		if(bits[sx][sy] == bits[sx][sy+1])
1108 			return(1);
1109 	return(0);
1110 }
1111 
1112 
DrawSameRect(x,y,sx,sy)1113 int DrawSameRect(x, y, sx, sy)
1114 int x;
1115 int y;
1116 int sx;
1117 int sy;
1118 {
1119 	EraseSameRect(x, y);
1120 	if(CheckSame(x, y, sx, sy))
1121 		DrawNextSameRect(x, y, sx, sy);
1122 	return(0);
1123 }
1124 
1125 
DrawNextSameRect(x,y,sx,sy)1126 int DrawNextSameRect(x, y, sx, sy)
1127 int x;
1128 int y;
1129 int sx;
1130 int sy;
1131 {
1132 	int c;
1133 
1134 	DrawRect(sx, sy);
1135 	sbits[sx][sy] = 1;
1136 	c = bits[sx][sy];
1137 	if(sx > 0 && c == bits[sx-1][sy] && sbits[sx-1][sy] == 0)
1138 	{
1139 		DrawNextSameRect(x, y, sx-1, sy);
1140 	}
1141 	if(sx < x - 1 && c == bits[sx+1][sy] && sbits[sx+1][sy] == 0)
1142 	{
1143 		DrawNextSameRect(x, y, sx+1, sy);
1144 	}
1145 	if(sy > 0 && c == bits[sx][sy-1] && sbits[sx][sy-1] == 0)
1146 	{
1147 		DrawNextSameRect(x, y, sx, sy-1);
1148 	}
1149 	if(sy < y - 1 && c == bits[sx][sy+1] && sbits[sx][sy+1] == 0)
1150 	{
1151 		DrawNextSameRect(x, y, sx, sy + 1);
1152 	}
1153 	return(0);
1154 }
1155 
1156 
CheckSelectSame(sx,sy)1157 int CheckSelectSame(sx, sy)
1158 int sx;
1159 int sy;
1160 {
1161 	int i, j;
1162 
1163 	for(j=0;j<sy;j++)
1164 		for(i=0;i<sx;i++)
1165 			if(sbits[i][j] == 1) return(1);
1166 	return(0);
1167 }
1168 
1169 
1170 
DeleteSame(x,y)1171 int DeleteSame(x, y)
1172 int x;
1173 int y;
1174 {
1175 	int i, j;
1176 	int num = 0;
1177 
1178 	for(j=0;j<y;j++)
1179 	{
1180 		for(i=0;i<x;i++)
1181 		{
1182 			if(sbits[i][j] == 1)
1183 			{
1184 				DeleteBit(i, j);
1185 				num ++;
1186 			}
1187 		}
1188 	}
1189 
1190 	if(num >= 2)
1191 	{
1192 		rest -= num;
1193 		score += (num-2)*(num-2);
1194 	}
1195 
1196 	for(i=x-1;i>=0&&bits[i][y-1]==0;i--);
1197 	if(i < 0)	/* perfect game */
1198 	{
1199 #ifdef BONUS1000
1200 		 score += 1000; /* original bonus points */
1201 #else /* !BONUS1000 */
1202 		 score  += same_width * same_height; /* bonus points */
1203 #endif /* BONUS1000 */
1204 	}
1205 	else
1206 	{
1207 		for(;i>=0;i--)
1208 		{
1209 			if(bits[i][y-1] == 0)
1210 				PushBits(x, y, i);
1211 		}
1212 	}
1213 	return(num);
1214 }
1215 
1216 
DeleteBit(sx,sy)1217 int DeleteBit(sx, sy)
1218 int sx;
1219 int sy;
1220 {
1221 	int i;
1222 
1223 	for(i=sy;i>0;i--)
1224 	{
1225 		bits[sx][i] = bits[sx][i-1];
1226 		sbits[sx][i] = sbits[sx][i-1];
1227 		DrawBit(sx, i, 0);
1228 	}
1229 	bits[sx][0] = 0;
1230 	sbits[sx][0] = 0;
1231 	DrawBit(sx, 0, 0);
1232 	return(0);
1233 }
1234 
PushBits(x,y,sx)1235 int PushBits(x, y, sx)
1236 int x;
1237 int y;
1238 int sx;
1239 {
1240 	int i, j;
1241 	for(i=sx;i<x-1;i++)
1242 	{
1243 		for(j=0;j<y;j++)
1244 		{
1245 			bits[i][j] = bits[i+1][j];
1246 			sbits[i][j] = sbits[i+1][j];
1247 			DrawBit(i, j, 0);
1248 		}
1249 	}
1250 	for(j=0;j<y;j++)
1251 	{
1252 		bits[x-1][j] = 0;
1253 		sbits[x-1][j] = 0;
1254 		DrawBit(x-1, j, 0);
1255 	}
1256 	return(0);
1257 }
1258 
GetColor(col)1259 unsigned long GetColor(col)
1260 char *col;
1261 {
1262 	XColor c0, c1;
1263 
1264 	XAllocNamedColor(dpy, cmap, col, &c1, &c0);
1265 	return(c1.pixel);
1266 }
1267 
SelectMenu(item,btn,def)1268 int SelectMenu(item, btn, def)
1269 struct item_struct *item;
1270 int btn;
1271 int def;
1272 {
1273 	Window pulldown;
1274 	int nmenu;
1275 	int pos_x, pos_y;
1276 	int btn_count = 0;
1277 	int menu_width = 0;
1278 	int pull_width;
1279 	int pull_height;
1280 	int i;
1281 	XEvent e;
1282 	int sel = -1, old_sel = -1;
1283 	Window dmyw;
1284 	int rx, ry, mx, my, mask;
1285 
1286 	pos_x = button_struct[btn].x;
1287 	pos_y = button_struct[btn].y + button_struct[btn].height + 2;
1288 	for(i=0;item[i].name != 0;i++)
1289 	{
1290 		if(strlen(item[i].name) > menu_width)
1291 			menu_width = strlen(item[i].name);
1292 	}
1293 	nmenu = i;
1294 	menu_width ++;
1295 
1296 	XSetFont(dpy, gc, font);
1297 
1298 	pull_width = char_width*(menu_width + 2) + 4;
1299 	pull_height = char_height*nmenu + 6;
1300 	pulldown = XCreateSimpleWindow(dpy, win, pos_x, pos_y,
1301 				pull_width, pull_height, 1, black, white);
1302 	XSelectInput(dpy, pulldown, ExposureMask | ButtonPressMask |
1303 		LeaveWindowMask | ButtonReleaseMask | PointerMotionMask);
1304 
1305 	XMapWindow(dpy, pulldown);
1306 	XRaiseWindow(dpy, pulldown);
1307 	while(1)
1308 	{
1309 		XPeekEvent(dpy, &e);
1310 		if(e.xany.window != pulldown && e.xany.window != button[btn])
1311 		{
1312 			/* if(e.type == LeaveNotify)  */
1313 			if(e.type == Expose || e.type == ButtonPress)
1314 			{
1315 				sel = -1;
1316 				goto select_return;
1317 			}
1318 			XNextEvent(dpy, &e);
1319 			continue;
1320 		}
1321 		XNextEvent(dpy, &e);
1322 		switch(e.type)
1323 		{
1324 		case Expose:
1325 			DrawMenuItem(pulldown, def, sel, nmenu,
1326 				menu_width, item);
1327 			break;
1328 		case EnterNotify:
1329 			if(btn_count == 1)
1330 			{
1331 				btn_count = 0;
1332 				continue;
1333 			}
1334 		case ButtonPress:
1335 			if(e.xany.window == button[btn])
1336 			{
1337 				sel = -1;
1338 			}
1339 			goto select_return;
1340 			break;
1341 		case LeaveNotify:
1342 			if(e.xany.window == button[btn])
1343 			{
1344 				if(btn_count == 1)
1345 					goto select_return;
1346 				btn_count ++;
1347 			}
1348 			/*break;*/
1349 		case MotionNotify:
1350 			XQueryPointer(dpy, pulldown, &dmyw, &dmyw, &rx, &ry,
1351 				&mx, &my, &mask);
1352 			sel = (my - 3) / char_height;
1353 			if(mx < 0 || mx > pull_width || my < 0 ||
1354 				my > pull_height)
1355 				sel = -1;
1356 			if(sel != old_sel)
1357 				DrawMenuItem(pulldown, def, sel, nmenu,
1358 					menu_width, item);
1359 			old_sel = sel;
1360 			break;
1361 		}
1362 	}
1363 
1364 select_return:
1365 	if((sel >= nmenu) ||
1366 		(sel >= 0 && (item[sel].lock || item[sel].name[0] == '\0')))
1367 		sel = -1;
1368 	if(sel != -1 && item[sel].func != 0 )
1369 	{
1370 		sel = (item[sel].func)();
1371 	}
1372 	XUnmapWindow(dpy, pulldown);
1373 	XDestroyWindow(dpy, pulldown);
1374 	return(sel);
1375 }
1376 
DrawMenuItem(pulldown,def,sel,nmenu,menu_width,item)1377 int DrawMenuItem(pulldown, def, sel, nmenu, menu_width, item)
1378 Window pulldown;
1379 int def;
1380 int sel;
1381 int nmenu;
1382 int menu_width;
1383 struct item_struct *item;
1384 {
1385 	int i, j;
1386 	char *menutmp;
1387 
1388 	if((menutmp = (char *)malloc(menu_width + 3)) == NULL)
1389 	{
1390 		fprintf(stderr,"%s: can't allocate memory.\n", program_name);
1391 		return(-1);
1392 	}
1393 
1394 	for(i=0;i<nmenu;i++)
1395 	{
1396 		if(item[i].name[0] == '\0')
1397 		{
1398 			XSetForeground(dpy, gc, black);
1399 			XDrawLine(dpy, pulldown, gc, 2, 6 + i*char_height + 3,
1400 			  (menu_width+2)*char_width, 6 + i*char_height + 3);
1401 			continue;
1402 		}
1403 		if(i == def)
1404 			sprintf(menutmp, "v %s", item[i].name);
1405 		else
1406 			sprintf(menutmp, "  %s", item[i].name);
1407 		for(j=strlen(item[i].name) + 2;j<menu_width + 2;j++)
1408 			menutmp[j] = ' ';
1409 		if(i == sel)
1410 		{
1411 			XSetForeground(dpy, gc, white);
1412 			XSetBackground(dpy, gc, black);
1413 		}
1414 		else
1415 		{
1416 			XSetForeground(dpy, gc, black);
1417 			XSetBackground(dpy, gc, white);
1418 		}
1419 		if(item[i].lock)
1420 		{
1421 			XSetForeground(dpy, gc, gray);
1422 			XSetBackground(dpy, gc, white);
1423 		}
1424 		XDrawImageString(dpy, pulldown, gc, 2, 12 + i*char_height + 3,
1425 			menutmp, menu_width + 2);
1426 	}
1427 	free(menutmp);
1428 	return(0);
1429 }
1430 
1431 
size_small()1432 int size_small()
1433 {
1434 	same_size = 0;
1435 	same_width = 15;
1436 	same_height = 8;
1437 	return(0);
1438 }
1439 
size_normal()1440 int size_normal()
1441 {
1442 	same_size = 1;
1443 	same_width = 20;
1444 	same_height = 10;
1445 	return(0);
1446 }
1447 
size_large()1448 int size_large()
1449 {
1450 	same_size = 2;
1451 	same_width = 25;
1452 	same_height = 15;
1453 	return(0);
1454 }
1455 
size_huge()1456 int size_huge()
1457 {
1458 	same_size = 3;
1459 	same_width = 30;
1460 	same_height = 20;
1461 	return(0);
1462 }
1463 
pic_marble()1464 int pic_marble()
1465 {
1466 	same_pic = 0;
1467 	same_other_pic = -1;
1468 	return(0);
1469 }
1470 
pic_head()1471 int pic_head()
1472 {
1473 	same_pic = 1;
1474 	same_other_pic = -1;
1475 	return(0);
1476 }
1477 
pic_face()1478 int pic_face()
1479 {
1480 	same_pic = 2;
1481 	same_other_pic = -1;
1482 	return(0);
1483 }
1484 
pic_other()1485 int pic_other()
1486 {
1487 	Window pulldown;
1488 	int nmenu, menu_width = 0;
1489 	int i;
1490 	Window dmyw;
1491 	int rx, ry, mx, my, mask;
1492 	int pull_width;
1493 	int pull_height;
1494 	XEvent e;
1495 	int sel = -1, old_sel = -1;
1496 
1497 	XQueryPointer(dpy, win, &dmyw, &dmyw, &rx, &ry, &mx, &my, &mask);
1498 	for(i=0;datafiles[i] != 0;i++)
1499 	{
1500 		if(strlen(datafiles[i]->title) > menu_width)
1501 			menu_width = strlen(datafiles[i]->title);
1502 	}
1503 	nmenu = i;
1504 	menu_width += 2;
1505 
1506 	XSetFont(dpy, gc, font);
1507 
1508 	pull_width = char_width*(menu_width) + 4;
1509 	pull_height = char_height*nmenu + 6;
1510 	pulldown = XCreateSimpleWindow(dpy, win, mx, my,
1511 				pull_width, pull_height, 1, black, white);
1512 	XSelectInput(dpy, pulldown, ExposureMask | ButtonPressMask |
1513 		LeaveWindowMask | ButtonReleaseMask | PointerMotionMask);
1514 
1515 	XMapWindow(dpy, pulldown);
1516 	XRaiseWindow(dpy, pulldown);
1517 	XFlush(dpy);
1518 	while(1)
1519 	{
1520 		XPeekEvent(dpy, &e);
1521 		if(e.xany.window != pulldown)
1522 		{
1523 			if(e.type == Expose || e.type == ButtonPress)
1524 			{
1525 				sel = -1;
1526 				goto select_return;
1527 			}
1528 			XNextEvent(dpy, &e);
1529 			continue;
1530 		}
1531 		XNextEvent(dpy, &e);
1532 		switch(e.type)
1533 		{
1534 		case Expose:
1535 			DrawSimpleMenuItem(pulldown, sel, nmenu,
1536 				menu_width, datafiles);
1537 			break;
1538 		case ButtonPress:
1539 			if(sel >= 0 && sel < nmenu)
1540 				same_pic = -1;
1541 			else
1542 				sel = -1;
1543 			goto select_return;
1544 			break;
1545 		case LeaveNotify:
1546 			sel = -1;
1547 			break;
1548 		case MotionNotify:
1549 			XQueryPointer(dpy, pulldown, &dmyw, &dmyw, &rx, &ry,
1550 				&mx, &my, &mask);
1551 			sel = (my - 3) / char_height;
1552 			if(mx < 0 || mx > pull_width || my < 0 ||
1553 				my > pull_height)
1554 				sel = -1;
1555 			if(sel != old_sel)
1556 			{
1557 				DrawSimpleMenuItem(pulldown, sel, nmenu,
1558 					menu_width, datafiles);
1559 			}
1560 			old_sel = sel;
1561 			break;
1562 		}
1563 		XFlush(dpy);
1564 	}
1565 
1566 select_return:
1567 
1568 	if((sel >= nmenu) || (sel >= 0 && datafiles[sel]->lock))
1569 		sel = -1;
1570 	XUnmapWindow(dpy, pulldown);
1571 	XDestroyWindow(dpy, pulldown);
1572 	same_other_pic = sel;
1573 	return(sel);
1574 }
1575 
DrawSimpleMenuItem(pulldown,sel,nmenu,menu_width,datafiles)1576 void DrawSimpleMenuItem(pulldown, sel, nmenu, menu_width, datafiles)
1577 Window pulldown;
1578 int sel;
1579 int nmenu;
1580 int menu_width;
1581 DataFile **datafiles;
1582 {
1583 	char tmpstr[256];
1584 	int i,j;
1585 
1586 	for(i=0;i<nmenu;i++)
1587 	{
1588 		if(datafiles[i]->lock)
1589 		{
1590 			XSetForeground(dpy, gc, gray);
1591 			XSetBackground(dpy, gc, white);
1592 		}
1593 		else if(i == sel)
1594 		{
1595 			XSetForeground(dpy, gc, white);
1596 			XSetBackground(dpy, gc, black);
1597 		}
1598 		else
1599 		{
1600 			XSetForeground(dpy, gc, black);
1601 			XSetBackground(dpy, gc, white);
1602 		}
1603 		sprintf(tmpstr," %s",datafiles[i]->title);
1604 		for(j=strlen(tmpstr);j<=menu_width;j++)
1605 			tmpstr[j] = ' ';
1606 		XDrawImageString(dpy, pulldown, gc, 2,
1607 			12 + i*char_height + 3, tmpstr, menu_width);
1608 	}
1609 }
1610 
1611 #ifdef DEBUG
DisplayWindowName(w)1612 int DisplayWindowName(w)
1613 Window w;
1614 {
1615 	if(w == win)
1616 		printf("win\n");
1617 	else if(w == same)
1618 		printf("same\n");
1619 	else
1620 		printf("0x%x\n", w);
1621 	return(0);
1622 }
1623 #endif /* DEBUG */
1624 
1625