rnd-20040816-1-src
[rocksndiamonds.git] / src / libem / init.c
1 /* 2000-08-10T18:03:54Z
2  *
3  * open X11 display and sound
4  */
5
6 #if 1
7 #include <X11/Xlib.h>
8 #include <X11/Xutil.h>
9 #include <X11/Xatom.h>
10 #include <X11/Xos.h>
11 #include <X11/Intrinsic.h>
12 #include <X11/keysymdef.h>
13 #endif
14
15 #include <X11/Xlib.h>
16 #include <X11/Xutil.h>
17 #include <X11/Xatom.h>
18 #include <X11/keysym.h>
19 #include <X11/cursorfont.h>
20 #include <X11/xpm.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <signal.h>
27 #include <string.h>
28 #include <errno.h>
29
30 #include "../libgame/platform.h"
31
32 #include "global.h"
33 #include "display.h"
34 #include "sample.h"
35
36 #if 0
37 Display *display;
38 Window xwindow;
39 #endif
40
41 #if 1
42 Bitmap *objBitmap;
43 Bitmap *botBitmap;
44 Bitmap *sprBitmap;
45 Bitmap *ttlBitmap;
46 #endif
47
48 #if 1
49 Bitmap *screenBitmap;
50 Bitmap *scoreBitmap;
51 #endif
52
53 Pixmap screenPixmap;
54 Pixmap scorePixmap;
55 Pixmap spriteBitmap;
56
57 Pixmap objPixmap;
58 Pixmap objmaskBitmap;
59 Pixmap botPixmap;
60 Pixmap botmaskBitmap;
61 Pixmap sprPixmap;
62 Pixmap sprmaskBitmap;
63 Pixmap ttlPixmap;
64 Pixmap ttlmaskBitmap;
65
66 GC screenGC;
67 GC scoreGC;
68 GC spriteGC;
69 GC antsGC;
70
71 Atom deleteAtom;
72
73 KeySym lastKeySym;
74
75 KeyCode northKeyCode[3];
76 KeyCode eastKeyCode[3];
77 KeyCode southKeyCode[3];
78 KeyCode westKeyCode[3];
79 KeyCode fireKeyCode[3];
80 KeyCode escKeyCode[1];
81
82 char play[SAMPLE_MAX];
83
84 static int sound_pid = -1;
85 int sound_pipe[2] = { -1, -1 }; /* for communication */
86 short *sound_data[SAMPLE_MAX]; /* pointer to sound data */
87 long sound_length[SAMPLE_MAX]; /* length of sound data */
88
89 static Screen *defaultScreen;
90 static Visual *defaultVisual;
91 static Colormap defaultColourmap;
92 static Window defaultRootWindow;
93 static unsigned int screenDepth;
94 static unsigned int screenWidth;
95 static unsigned int screenHeight;
96 static unsigned long screenBlackPixel;
97 static unsigned long screenWhitePixel;
98
99 #if 0
100 static XSizeHints sizeHints;
101 static XSetWindowAttributes setWindowAttributes;
102 static XWMHints wmHints;
103 static XVisualInfo visualInfo;
104 #endif
105 static XGCValues gcValues;
106
107 static Colormap privateColourmap;
108 static Cursor cursor;
109 static XColor *privateColours;
110 static unsigned char *privateFlags;
111 static int privateNumColours;
112
113 static XColor redColour;
114 static XColor whiteColour;
115 static int gotRed;
116 static int gotWhite;
117
118 #if 1
119 static Bitmap *pcxBitmaps[4];
120 #endif
121
122 #if 0
123 static Pixmap xpmPixmaps[4];
124 static Pixmap xpmBitmaps[4];
125 static XpmAttributes xpmAttributes[4];
126 static int xpmGot[4];
127 #endif
128
129 static int xpmAllocColourFunc(Display *, Colormap, char *, XColor *, void *);
130 static int xpmFreeColoursFunc(Display *, Colormap, unsigned long *, int, void *);
131
132 static KeyCode keycodes[16];
133
134 #if 0
135 static const char *xpmNames[4] = { "object.xpm", "score.xpm", "sprite.xpm", "title.xpm" };
136 #endif
137
138 #if 1
139 static const char *pcxNames[4] = { "object.pcx", "score.pcx", "sprite.pcx", "title.pcx" };
140 #endif
141
142 static const int xpmCloseness[4] = { 10000, 10000, 40000, 50000 };
143 static const KeySym keysyms[16] = {
144         XK_Up, XK_KP_Up, XK_r, /* north */
145         XK_Right, XK_KP_Right, XK_g, /* east */
146         XK_Down, XK_KP_Down, XK_f, /* south */
147         XK_Left, XK_KP_Left, XK_d, /* west */
148         XK_Shift_L, XK_Control_R, XK_space, /* fire */
149         XK_Escape /* escape */
150 };
151 static const char *sound_names[SAMPLE_MAX] = {
152         "00.blank.au","01.roll.au","02.stone.au","03.nut.au","04.crack.au",
153         "05.bug.au","06.tank.au","07.android.au","08.spring.au","09.slurp.au",
154         "10.eater.au","11.alien.au","12.collect.au","13.diamond.au","14.squash.au",
155         "15.drip.au","16.push.au","17.dirt.au","18.acid.au","19.ball.au",
156         "20.grow.au","21.wonder.au","22.door.au","23.exit.au","24.dynamite.au",
157         "25.tick.au","26.press.au","27.wheel.au","28.boom.au","29.time.au",
158         "30.die.au"
159 };
160 static const int sound_volume[SAMPLE_MAX] = {
161         20,100,100,100,100,20,20,100,100,100,
162         50,100,100,100,100,100,100,100,100,100,
163         100,20,100,100,100,100,100,20,100,100,
164         100
165 };
166
167 int open_all(void)
168 {
169         char name[MAXNAME+2];
170 #if 0
171         void *dummyptr;
172         int dummyint;
173 #endif
174         int i;
175
176 #if 0
177         display = XOpenDisplay(arg_display);
178         if(display == 0) {
179                 fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, XDisplayName(arg_display), "failed to open display", strerror(errno));
180                 return(1);
181         }
182 #endif
183
184         defaultScreen = DefaultScreenOfDisplay(display);
185         defaultVisual = DefaultVisualOfScreen(defaultScreen);
186         defaultColourmap = DefaultColormapOfScreen(defaultScreen);
187         defaultRootWindow = RootWindowOfScreen(defaultScreen);
188         screenDepth = DefaultDepthOfScreen(defaultScreen);
189         screenWidth = WidthOfScreen(defaultScreen);
190         screenHeight = HeightOfScreen(defaultScreen);
191         screenBlackPixel = BlackPixelOfScreen(defaultScreen);
192         screenWhitePixel = WhitePixelOfScreen(defaultScreen);
193
194 #if 0
195         if(arg_install) {
196                 visualInfo.visualid = XVisualIDFromVisual(defaultVisual);
197                 dummyptr = XGetVisualInfo(display, VisualIDMask, &visualInfo, &dummyint);
198                 if(dummyptr == 0) {
199                         fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, XDisplayName(arg_display), "failed to get visual info", strerror(errno));
200                         return(1);
201                 }
202                 memcpy(&visualInfo, dummyptr, sizeof(visualInfo));
203                 XFree(dummyptr);
204
205                 if(visualInfo.class != PseudoColor) {
206                         fprintf(stderr, "%s: \"%s\": %s\n", progname, XDisplayName(arg_display), "private colourmap only supported for pseudocolour display");
207                         return(1);
208                 }
209
210                 privateColourmap = XCreateColormap(display, defaultRootWindow, defaultVisual, AllocAll);
211                 if(privateColourmap == 0) {
212                         fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, XDisplayName(arg_display), "failed to create colourmap", strerror(errno));
213                         return(1);
214                 }
215
216                 privateNumColours = visualInfo.colormap_size;
217
218                 privateColours = malloc(privateNumColours * sizeof(XColor));
219                 if(privateColours == 0) {
220                         fprintf(stderr, "%s: %s (%d): %s\n", progname, "malloc failed", privateNumColours * sizeof(XColor), strerror(errno));
221                         return(1);
222                 }
223                 for(dummyint = 0; dummyint < privateNumColours; dummyint++) privateColours[dummyint].pixel = dummyint;
224                 XQueryColors(display, defaultColourmap, privateColours, privateNumColours);
225                 XStoreColors(display, privateColourmap, privateColours, privateNumColours);
226
227                 privateFlags = malloc(privateNumColours);
228                 if(privateFlags == 0) {
229                         fprintf(stderr, "%s: %s (%d): %s\n", progname, "malloc failed", privateNumColours, strerror(errno));
230                         return(1);
231                 }
232                 memset(privateFlags, 0, privateNumColours);
233                 privateFlags[0] = 1; /* first two entries (black and white) are already allocated */
234                 privateFlags[1] = 1;
235         }
236
237         sizeHints.flags = PSize | PMinSize | PMaxSize;
238         sizeHints.width = 20 * TILEX;
239         sizeHints.height = 12 * TILEY + SCOREY;
240         sizeHints.min_width = sizeHints.max_width = sizeHints.width;
241         sizeHints.min_height = sizeHints.max_height = sizeHints.height;
242         if(arg_geometry) {
243                 dummyint = XWMGeometry(display, XScreenNumberOfScreen(defaultScreen), arg_geometry, 0, 2, &sizeHints, &sizeHints.x, &sizeHints.y, &dummyint, &dummyint, &sizeHints.win_gravity);
244                 if(dummyint & (XValue | YValue)) sizeHints.flags |= USPosition | PWinGravity;
245         }
246
247         xwindow = XCreateWindow(display, defaultRootWindow, sizeHints.x, sizeHints.y, sizeHints.width, sizeHints.height, 2, screenDepth, InputOutput, CopyFromParent, 0, 0);
248         if(xwindow == 0) {
249                 fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, XDisplayName(arg_display), "failed to open window", strerror(errno));
250                 return(1);
251         }
252
253         setWindowAttributes.background_pixel = screenBlackPixel;
254         setWindowAttributes.border_pixel = screenWhitePixel;
255         setWindowAttributes.backing_store = NotUseful;
256         setWindowAttributes.override_redirect = False;
257         setWindowAttributes.event_mask = KeyPressMask | EnterWindowMask | LeaveWindowMask | ExposureMask;
258         setWindowAttributes.colormap = privateColourmap ? privateColourmap : defaultColourmap;
259         XChangeWindowAttributes(display, xwindow, CWBackPixel | CWBorderPixel | CWBackingStore | CWOverrideRedirect | CWEventMask | CWColormap, &setWindowAttributes);
260
261         XStoreName(display, xwindow, "Emerald Mine");
262
263         wmHints.flags = InputHint | StateHint;
264         wmHints.input = True;
265         wmHints.initial_state = NormalState;
266         XSetWMHints(display, xwindow, &wmHints);
267
268         XSetWMNormalHints(display, xwindow, &sizeHints);
269
270         deleteAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
271         XSetWMProtocols(display, xwindow, &deleteAtom, 1);
272
273         cursor = XCreateFontCursor(display, XC_trek);
274         if(cursor) XDefineCursor(display, xwindow, cursor);
275
276         XMapWindow(display, xwindow);
277 #endif
278
279 #if 0
280         for(i = 0; i < 4; i++) {
281                 name[MAXNAME] = 0;
282                 if(arg_basedir) {
283                         snprintf(name, MAXNAME+2, "%s/%s/%s", arg_basedir, EM_GFX_DIR, xpmNames[i]);
284                 } else {
285                         snprintf(name, MAXNAME+2, "%s/%s", EM_GFX_DIR, xpmNames[i]);
286                 }
287                 if(name[MAXNAME]) snprintf_overflow("read graphics/ files");
288
289                 xpmAttributes[i].valuemask = XpmColormap | XpmReturnAllocPixels | XpmExactColors | XpmCloseness | XpmAllocColor | XpmFreeColors;
290                 xpmAttributes[i].colormap = privateColourmap ? privateColourmap : defaultColourmap;
291                 xpmAttributes[i].exactColors = False;
292                 xpmAttributes[i].closeness = xpmCloseness[i];
293                 xpmAttributes[i].alloc_color = xpmAllocColourFunc;
294                 xpmAttributes[i].free_colors = xpmFreeColoursFunc;
295                 dummyint = XpmReadFileToPixmap(display, xwindow, name, &xpmPixmaps[i], &xpmBitmaps[i], &xpmAttributes[i]);
296                 if(dummyint) {
297                         fprintf(stderr, "%s: \"%s\": \"%s\": %s: %s: %s\n", progname, XDisplayName(arg_display), name, "failed to read xpm", XpmGetErrorString(dummyint), strerror(errno));
298                         return(1);
299                 }
300                 xpmGot[i] = 1;
301         }
302 #endif
303
304         for(i = 0; i < 4; i++)
305         {
306           name[MAXNAME] = 0;
307           snprintf(name, MAXNAME+2, "%s/%s", EM_GFX_DIR, pcxNames[i]);
308
309           if (name[MAXNAME])
310             snprintf_overflow("read graphics/ files");
311
312           if ((pcxBitmaps[i] = LoadImage(name)) == NULL)
313           {
314             printf("::: LoadImage() failed for file '%s'\n", name);
315             return 1;
316           }
317         }
318
319         objBitmap = pcxBitmaps[0];
320         botBitmap = pcxBitmaps[1];
321         sprBitmap = pcxBitmaps[2];
322         ttlBitmap = pcxBitmaps[3];
323
324 #if 0
325         objPixmap = xpmPixmaps[0];
326         botPixmap = xpmPixmaps[1];
327         sprPixmap = xpmPixmaps[2];
328         ttlPixmap = xpmPixmaps[3];
329         objmaskBitmap = xpmBitmaps[0];
330         botmaskBitmap = xpmBitmaps[1];
331         sprmaskBitmap = xpmBitmaps[2];
332         ttlmaskBitmap = xpmBitmaps[3];
333 #else
334         objPixmap = pcxBitmaps[0]->drawable;
335         botPixmap = pcxBitmaps[1]->drawable;
336         sprPixmap = pcxBitmaps[2]->drawable;
337         ttlPixmap = pcxBitmaps[3]->drawable;
338         objmaskBitmap = pcxBitmaps[0]->clip_mask;
339         botmaskBitmap = pcxBitmaps[1]->clip_mask;
340         sprmaskBitmap = pcxBitmaps[2]->clip_mask;
341         ttlmaskBitmap = pcxBitmaps[3]->clip_mask;
342 #endif
343
344 #if 1
345         screenBitmap = CreateBitmap(22 * TILEX, 14 * TILEY, DEFAULT_DEPTH);
346         scoreBitmap = CreateBitmap(20 * TILEX, SCOREY, DEFAULT_DEPTH);
347 #endif
348
349         screenPixmap = XCreatePixmap(display, xwindow, 22 * TILEX, 14 * TILEY, screenDepth);
350         if(screenPixmap == 0) {
351                 fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, XDisplayName(arg_display), "failed to create pixmap", strerror(errno));
352                 return(1);
353         }
354
355         scorePixmap = XCreatePixmap(display, xwindow, 20 * TILEX, SCOREY, screenDepth);
356         if(scorePixmap == 0) {
357                 fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, XDisplayName(arg_display), "failed to create pixmap", strerror(errno));
358                 return(1);
359         }
360
361         spriteBitmap = XCreatePixmap(display, xwindow, TILEX, TILEY, 1);
362         if(spriteBitmap == 0) {
363                 fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, XDisplayName(arg_display), "failed to create pixmap", strerror(errno));
364                 return(1);
365         }
366
367         redColour.pixel = screenWhitePixel;
368         whiteColour.pixel = screenBlackPixel;
369         gotRed = (xpmAllocColourFunc(display, privateColourmap ? privateColourmap : defaultColourmap, "red", &redColour, 0) > 0);
370         gotWhite = (xpmAllocColourFunc(display, privateColourmap ? privateColourmap : defaultColourmap, "white", &whiteColour, 0) > 0);
371
372         gcValues.graphics_exposures = False;
373         screenGC = XCreateGC(display, screenPixmap, GCGraphicsExposures, &gcValues);
374         if(screenGC == 0) {
375                 fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, XDisplayName(arg_display), "failed to create graphics context", strerror(errno));
376                 return(1);
377         }
378
379         gcValues.graphics_exposures = False;
380         scoreGC = XCreateGC(display, scorePixmap, GCGraphicsExposures, &gcValues);
381         if(scoreGC == 0) {
382                 fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, XDisplayName(arg_display), "failed to create graphics context", strerror(errno));
383                 return(1);
384         }
385
386         gcValues.function = objmaskBitmap ? GXcopyInverted : sprmaskBitmap ? GXcopy : GXset;
387         gcValues.graphics_exposures = False;
388         spriteGC = XCreateGC(display, spriteBitmap, GCFunction | GCGraphicsExposures, &gcValues);
389         if(spriteGC == 0) {
390                 fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, XDisplayName(arg_display), "failed to create graphics context", strerror(errno));
391                 return(1);
392         }
393
394         gcValues.foreground = redColour.pixel;
395         gcValues.background = whiteColour.pixel;
396         gcValues.line_style = LineDoubleDash;
397         gcValues.graphics_exposures = False;
398         antsGC = XCreateGC(display, screenPixmap, GCForeground | GCBackground | GCLineStyle | GCGraphicsExposures, &gcValues);
399         if(antsGC == 0) {
400                 fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, XDisplayName(arg_display), "failed to create graphics context", strerror(errno));
401                 return(1);
402         }
403
404         for(i = 0; i < 16; i++) {
405                 keycodes[i] = XKeysymToKeycode(display, keysyms[i]);
406         }
407         for(i = 0; i < 3; i++) northKeyCode[i] = keycodes[i + 0];
408         for(i = 0; i < 3; i++) eastKeyCode[i] = keycodes[i + 3];
409         for(i = 0; i < 3; i++) southKeyCode[i] = keycodes[i + 6];
410         for(i = 0; i < 3; i++) westKeyCode[i] = keycodes[i + 9];
411         for(i = 0; i < 3; i++) fireKeyCode[i] = keycodes[i + 12];
412         for(i = 0; i < 1; i++) escKeyCode[i] = keycodes[i + 15];
413
414 #if defined(PLATFORM_LINUX) || defined(PLATFORM_BSD)
415         if(arg_silence == 0) {
416                 for(i = 0; i < SAMPLE_MAX; i++) {
417                         name[MAXNAME] = 0;
418                         if(arg_basedir) {
419                                 snprintf(name, MAXNAME+2, "%s/%s/%s", arg_basedir, EM_SND_DIR, sound_names[i]);
420                         } else {
421                                 snprintf(name, MAXNAME+2, "%s/%s", EM_SND_DIR, sound_names[i]);
422                         }
423                         if(name[MAXNAME]) snprintf_overflow("read sounds/ directory");
424
425                         if(read_sample(name, &sound_data[i], &sound_length[i])) return(1);
426
427                         {
428                                 short *ptr, *stop;
429                                 int mult = sound_volume[i] * 65536 / (100 * MIXER_MAX);
430                                 stop = sound_data[i] + sound_length[i];
431                                 for(ptr = sound_data[i]; ptr < stop; ptr++) *ptr = (*ptr * mult) / 65536;
432                         }
433                 }
434
435                 if(pipe(sound_pipe) == -1) {
436                         fprintf(stderr, "%s: %s: %s\n", progname, "unable to create sound pipe", strerror(errno));
437                         return(1);
438                 }
439                 sound_pid = fork();
440                 if(sound_pid == -1) {
441                         fprintf(stderr, "%s: %s: %s\n", progname, "unable to fork sound thread", strerror(errno));
442                         return(1);
443                 }
444                 close(sound_pipe[sound_pid == 0]); sound_pipe[sound_pid == 0] = -1;
445                 if(sound_pid == 0) _exit(sound_thread());
446                 signal(SIGPIPE, SIG_IGN); /* dont crash if sound process dies */
447         }
448 #endif /* defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) */
449
450         return(0);
451 }
452
453 void close_all(void)
454 {
455         int i;
456
457         if(sound_pid != -1) {
458                 kill(sound_pid, SIGTERM);
459                 waitpid(sound_pid, 0, 0);
460         }
461         if(sound_pipe[0] != -1) close(sound_pipe[0]);
462         if(sound_pipe[1] != -1) close(sound_pipe[1]);
463         for(i = 0; i < SAMPLE_MAX; i++) if(sound_data[i]) free(sound_data[i]);
464
465 #if 0
466         for(i = 0; i < 4; i++) if(xpmPixmaps[i]) XFreePixmap(display, xpmPixmaps[i]);
467         for(i = 0; i < 4; i++) if(xpmBitmaps[i]) XFreePixmap(display, xpmBitmaps[i]);
468         for(i = 0; i < 4; i++) if(xpmGot[i]) {
469                 xpmFreeColoursFunc(display, xpmAttributes[i].colormap, xpmAttributes[i].alloc_pixels, xpmAttributes[i].nalloc_pixels, 0);
470                 XpmFreeAttributes(&xpmAttributes[i]);
471         }
472 #endif
473
474         if(gotRed) xpmFreeColoursFunc(display, privateColourmap ? privateColourmap : defaultColourmap, &redColour.pixel, 1, 0);
475         if(gotWhite) xpmFreeColoursFunc(display, privateColourmap ? privateColourmap : defaultColourmap, &whiteColour.pixel, 1, 0);
476
477         if(screenGC) XFreeGC(display, screenGC);
478         if(scoreGC) XFreeGC(display, scoreGC);
479         if(spriteGC) XFreeGC(display, spriteGC);
480         if(antsGC) XFreeGC(display, antsGC);
481         if(screenPixmap) XFreePixmap(display, screenPixmap);
482         if(scorePixmap) XFreePixmap(display, scorePixmap);
483         if(spriteBitmap) XFreePixmap(display, spriteBitmap);
484         if(xwindow) XDestroyWindow(display, xwindow);
485         if(cursor) XFreeCursor(display, cursor);
486         if(privateColourmap) XFreeColormap(display, privateColourmap);
487         if(privateColours) free(privateColours);
488         if(privateFlags) free(privateFlags);
489         if(display) XCloseDisplay(display);
490 }
491
492 /* ---------------------------------------------------------------------- */
493
494 void sound_play(void)
495 {
496         if(sound_pipe[1] != -1) {
497                 if(write(sound_pipe[1], &play, sizeof(play)) == -1) {
498                         fprintf(stderr, "%s: %s: %s\n", progname, "write sound", strerror(errno));
499                         if(sound_pipe[0] != -1) { close(sound_pipe[0]); sound_pipe[0] = -1; }
500                         if(sound_pipe[1] != -1) { close(sound_pipe[1]); sound_pipe[1] = -1; }
501                 }
502         }
503         memset(play, 0, sizeof(play));
504 }
505
506 /* ---------------------------------------------------------------------- */
507
508 static int xpmAllocColourFunc(Display *display, Colormap colourmap, char *colourname, XColor *xcolour, void *closure)
509 {
510         int i, match;
511         int r,g,b;
512         long best, sum;
513
514         if(colourname) if(XParseColor(display, colourmap, colourname, xcolour) == 0) return(-1); /* invalid name */
515         if(colourmap != privateColourmap) return(XAllocColor(display, colourmap, xcolour) != 0);
516
517 /* first try to find an exact match */
518         match = -1;
519         for(i = 0; i < privateNumColours; i++) {
520                 if(privateColours[i].red == xcolour->red && privateColours[i].green == xcolour->green && privateColours[i].blue == xcolour->blue) match = i;
521         }
522         if(match != -1) {
523                 privateFlags[match] = 1;
524                 xcolour->pixel = privateColours[match].pixel;
525                 return(1);
526         }
527
528 /* then find an unallocated colour that is close to what we want */
529         match = -1;
530         best = 1000000;
531         for(i = 0; i < privateNumColours; i++) {
532                 if(privateFlags[i]) continue; /* skip if it is already allocated */
533                 r = (privateColours[i].red - xcolour->red) / 256;
534                 g = (privateColours[i].green - xcolour->green) / 256;
535                 b = (privateColours[i].blue - xcolour->blue) / 256;
536                 sum = r * r + g * g + b * b;
537                 if(sum < best) {
538                         best = sum;
539                         match = i;
540                 }
541         }
542         if(match != -1) {
543                 privateFlags[match] = 1;
544                 privateColours[match].red = xcolour->red;
545                 privateColours[match].green = xcolour->green;
546                 privateColours[match].blue = xcolour->blue;
547                 XStoreColor(display, colourmap, &privateColours[match]);
548                 xcolour->pixel = privateColours[match].pixel;
549                 return(1); /* found a close match */
550         }
551
552 /* if all else fails, just find the closest colour and return it */
553         match = -1;
554         best = 1000000;
555         for(i = 0; i < privateNumColours; i++) {
556                 r = (privateColours[i].red - xcolour->red) / 256;
557                 g = (privateColours[i].green - xcolour->green) / 256;
558                 b = (privateColours[i].blue - xcolour->blue) / 256;
559                 sum = r * r + g * g + b * b;
560                 if(sum < best) {
561                         best = sum;
562                         match = i;
563                 }
564         }
565         if(match != -1) {
566                 xcolour->red = privateColours[match].red;
567                 xcolour->green = privateColours[match].green;
568                 xcolour->blue = privateColours[match].blue;
569                 xcolour->pixel = privateColours[match].pixel;
570                 return(1); /* best we could do */
571         }
572         return(0); /* still didnt find one, give up */
573 }
574
575 static int xpmFreeColoursFunc(Display *display, Colormap colourmap, unsigned long *pixels, int npixels, void *closure)
576 {
577         if(colourmap != privateColourmap) XFreeColors(display, colourmap, pixels, npixels, 0);
578         return(1); /* non-zero for success */
579 }