1 #if 0
2 static const char sccsid[] = "@(#)color.c	4.00 97/01/01 xlockmore";
3 
4 #endif
5 
6 /*-
7  * color.c - extracted from swirl.c, xlock.c and util.c
8  *
9  * See xlock.c for copying information.
10  *
11  * xlock.c and util.c Copyright (c) 1988-91 by Patrick J. Naughton.
12  * swirl.c Copyright (c) 1994 M.Dobie <mrd@ecs.soton.ac.uk>
13  *
14  */
15 
16 #include "xlock.h"
17 #include "color.h"
18 
19 /* Formerly in util.c */
20 /*-
21  * Create an HSB ramp.
22  *
23  * Revision History:
24  * Changes maintained by David Bagley <bagleyd AT verizon.net>
25  * 22-Jun-94: Modified for VMS
26  *            <Anthony.D.Clarke@Support.Hatfield.Raytheon.bae.eurokom.ie>
27  * Changes of Patrick J. Naughton
28  * 29-Jul-90: renamed hsbramp.c from HSBmap.c
29  *	      minor optimizations.
30  * 01-Sep-88: Written.
31  */
32 
33 static void
hsb2rgb(double H,double S,double B,unsigned char * r,unsigned char * g,unsigned char * b)34 hsb2rgb(double H, double S, double B,
35 	unsigned char *r, unsigned char *g, unsigned char *b)
36 {
37 	int         i;
38 	double      f, bb;
39 	unsigned char p, q, t;
40 
41 	H -= floor(H);		/* remove anything over 1 */
42 	H *= 6.0;
43 	i = (int) floor(H);	/* 0..5 */
44 	f = H - (float) i;	/* f = fractional part of H */
45 	bb = 255.0 * B;
46 	p = (unsigned char) (bb * (1.0 - S));
47 	q = (unsigned char) (bb * (1.0 - (S * f)));
48 	t = (unsigned char) (bb * (1.0 - (S * (1.0 - f))));
49 	switch (i) {
50 		case 0:
51 			*r = (unsigned char) bb;
52 			*g = t;
53 			*b = p;
54 			break;
55 		case 1:
56 			*r = q;
57 			*g = (unsigned char) bb;
58 			*b = p;
59 			break;
60 		case 2:
61 			*r = p;
62 			*g = (unsigned char) bb;
63 			*b = t;
64 			break;
65 		case 3:
66 			*r = p;
67 			*g = q;
68 			*b = (unsigned char) bb;
69 			break;
70 		case 4:
71 			*r = t;
72 			*g = p;
73 			*b = (unsigned char) bb;
74 			break;
75 		case 5:
76 			*r = (unsigned char) bb;
77 			*g = p;
78 			*b = q;
79 			break;
80 	}
81 }
82 
83 
84 /*-
85  * Input is two points in HSB color space and a count
86  * of how many discreet rgb space values the caller wants.
87  *
88  * Output is that many rgb triples which describe a linear
89  * interpolate ramp between the two input colors.
90  */
91 #ifdef WIN32
92 /*-
93  * make sure this function is NOT static under WIN32. We use it to
94  * create the colortable in WIN32 specific stuff in xlock.c
95  */
96 void
97 #else
98 static void
99 #endif
hsbramp(double h1,double s1,double b1,double h2,double s2,double b2,int count,unsigned char * red,unsigned char * green,unsigned char * blue)100 hsbramp(double h1, double s1, double b1, double h2, double s2, double b2,
101     int count, unsigned char *red, unsigned char *green, unsigned char *blue)
102 {
103 	double      dh, ds, db;
104 
105 	dh = (h2 - h1) / count;
106 	ds = (s2 - s1) / count;
107 	db = (b2 - b1) / count;
108 	while (count--) {
109 		hsb2rgb(h1, s1, b1, red++, green++, blue++);
110 		h1 += dh;
111 		s1 += ds;
112 		b1 += db;
113 	}
114 }
115 
116 
117 /* Formerly in xlock.c */
118 
119 unsigned long
allocPixel(Display * display,Colormap cmap,char * name,char * def)120 allocPixel(Display * display, Colormap cmap, char *name, char *def)
121 {
122 	XColor      col, tmp;
123 
124 	(void) XParseColor(display, cmap, name, &col);
125 	if (!XAllocColor(display, cmap, &col)) {
126 		(void) fprintf(stderr, "could not allocate: %s, using %s instead\n",
127 			       name, def);
128 		(void) XAllocNamedColor(display, cmap, def, &col, &tmp);
129 	}
130 	return col.pixel;
131 }
132 
133 static void
monoColormap(Screen * scr,ScreenInfo * si,char * foreground,char * background)134 monoColormap(Screen * scr, ScreenInfo * si, char *foreground, char *background)
135 {
136 	si->black_pixel = BlackPixelOfScreen(scr);
137 	si->white_pixel = WhitePixelOfScreen(scr);
138 	if (strcmp(foreground, "White") == 0 || strcmp(foreground, "white") == 0 ||
139 	    strcmp(background, "Black") == 0 || strcmp(background, "black") == 0) {
140 		si->fg_pixel = WhitePixelOfScreen(scr);
141 		si->bg_pixel = BlackPixelOfScreen(scr);
142 	} else {
143 		si->fg_pixel = BlackPixelOfScreen(scr);
144 		si->bg_pixel = WhitePixelOfScreen(scr);
145 	}
146 	si->pixels[0] = WhitePixelOfScreen(scr);
147 	si->pixels[1] = BlackPixelOfScreen(scr);
148 	si->npixels = 2;
149 }
150 
151 extern char *foreground;
152 extern char *background;
153 #ifdef USE_DTSAVER
154 extern Bool dtsaver;
155 #endif
156 
157 void
fixColormap(ModeInfo * mi,int ncolors,float saturation,Bool mono,Bool install,Bool inroot,Bool inwindow,Bool verbose)158 fixColormap(ModeInfo * mi, int ncolors, float saturation,
159 	    Bool mono, Bool install, Bool inroot, Bool inwindow, Bool verbose)
160 {
161 	Display    *display = MI_DISPLAY(mi);
162 	Window     window = MI_WINDOW(mi);
163 	Screen     *scr = MI_SCREENPTR(mi);
164 	Colormap    cmap = MI_COLORMAP(mi);
165 	Colormap    dcmap = DefaultColormapOfScreen(scr);
166 	XColor      xcolor;
167 	unsigned char *red = (unsigned char *) NULL,
168 		*green = (unsigned char *) NULL,
169 		*blue = (unsigned char *) NULL;
170 	int         colorcount, i, fixed, visualclass;
171 
172 #ifndef COMPLIANT_COLORMAP
173 	Bool        retry = False;
174 
175 #endif
176 
177 	if (mono || CellsOfScreen(scr) <= 2) {
178 		if (MI_PIXELS(mi))
179 			return;
180 		if ((MI_PIXELS(mi) = (unsigned long *) calloc(2,
181 				sizeof (unsigned long))) == NULL) {
182 			(void) fprintf(stderr, "could not get the 2 colors for mono\n");
183 		}
184 
185 		monoColormap(scr, MI_SCREENINFO(mi), foreground, background);
186 		return;
187 	}
188 	colorcount = ncolors;
189 	if (((  red = (unsigned char *) calloc(ncolors,
190 			sizeof (unsigned char))) == NULL) ||
191 	    ((green = (unsigned char *) calloc(ncolors,
192 			sizeof (unsigned char))) == NULL) ||
193 	    (( blue = (unsigned char *) calloc(ncolors,
194 			sizeof (unsigned char))) == NULL)) {
195 		(void) fprintf(stderr, "could not get the %d colors\n", ncolors);
196 		if (red != NULL)
197 			free(red);
198 		if (green != NULL)
199 			free(green);
200 		return;
201 	}
202 
203 	visualclass = MI_VISUALCLASS(mi);
204 	fixed = (visualclass == StaticGray) || (visualclass == StaticColor) ||
205 		(visualclass == TrueColor);
206 	if (
207 #ifdef USE_DTSAVER
208 		   dtsaver ||	/* needs to be in focus without mouse */
209 
210 #endif
211 		   inroot || (!install && !fixed) || cmap == None) {
212 		cmap = dcmap;
213 	}
214 	if (cmap != dcmap && MI_PIXELS(mi)) {
215 		XFreeColors(display, cmap, MI_PIXELS(mi), MI_NPIXELS(mi), 0);
216 #ifndef COMPLIANT_COLORMAP
217 		XFreeColors(display, cmap, &(MI_BLACK_PIXEL(mi)), 1, 0);
218 		XFreeColors(display, cmap, &(MI_WHITE_PIXEL(mi)), 1, 0);
219 #endif
220 		XFreeColors(display, cmap, &(MI_BG_PIXEL(mi)), 1, 0);
221 		XFreeColors(display, cmap, &(MI_FG_PIXEL(mi)), 1, 0);
222 	}
223 	/* else if (cmap) { (void) printf("cmap: this case is possible?\n");  } */
224 	if (MI_PIXELS(mi))
225 		free(MI_PIXELS(mi));
226 	if ((MI_PIXELS(mi) = (unsigned long *) calloc(ncolors,
227 			sizeof (unsigned long))) == NULL) {
228 		(void) fprintf(stderr, "could not get the %d colors\n", ncolors);
229 	}
230 	/* "allocate" the black and white pixels, so that they
231 	   will be included by XCopyColormapAndFree() if it gets called */
232 #ifdef COMPLIANT_COLORMAP
233 	MI_BLACK_PIXEL(mi) = BlackPixelOfScreen(scr);
234 	MI_WHITE_PIXEL(mi) = WhitePixelOfScreen(scr);
235 #else
236 	MI_BLACK_PIXEL(mi) = allocPixel(display, cmap, (char *) "Black", (char *) "Black");
237 	MI_WHITE_PIXEL(mi) = allocPixel(display, cmap, (char *) "White", (char *) "White");
238 #endif
239 	MI_BG_PIXEL(mi) = allocPixel(display, cmap, background, (char *) "White");
240 	MI_FG_PIXEL(mi) = allocPixel(display, cmap, foreground, (char *) "Black");
241 	hsbramp(0.0, saturation, 1.0, 1.0, saturation, 1.0, colorcount,
242 		red, green, blue);
243 
244 	MI_NPIXELS(mi) = 0;
245 	for (i = 0; i < colorcount; i++) {
246 		xcolor.red = red[i] << 8;
247 		xcolor.green = green[i] << 8;
248 		xcolor.blue = blue[i] << 8;
249 		xcolor.flags = DoRed | DoGreen | DoBlue;
250 
251 		if (!XAllocColor(display, cmap, &xcolor)) {
252 #ifdef COMPLIANT_COLORMAP
253 			if (!install || cmap != dcmap)
254 				break;
255 			if ((cmap = XCopyColormapAndFree(display, cmap)) == dcmap)
256 				break;
257 			if (verbose)
258 				(void) fprintf(stderr, "using private colormap\n");
259 			if (!XAllocColor(display, cmap, &xcolor))
260 				break;
261 #else
262 			if (verbose)
263 				(void) fprintf(stderr, "ran out of colors on colormap\n");
264 			if ((saturation != 1.0 || ncolors != 64) && MI_NPIXELS(mi) < 2) {
265 				if (verbose)
266 					(void) fprintf(stderr,
267 						       "retrying with saturation = 1.0 and ncolors = 64\n");
268 				retry = True;
269 			}
270 			break;
271 #endif
272 		}
273 		MI_PIXELS(mi)[i] = xcolor.pixel;
274 		MI_NPIXELS(mi)++;
275 	}
276 	free(red);
277 	free(green);
278 	free(blue);
279 	if (verbose)
280 		(void) fprintf(stderr, "%d pixel%s allocated\n", MI_NPIXELS(mi),
281 			       (MI_NPIXELS(mi) == 1) ? "" : "s");
282 	if (MI_NPIXELS(mi) <= 4) {
283 		XFreeColors(display, cmap, MI_PIXELS(mi), MI_NPIXELS(mi), 0);
284 #ifndef COMPLIANT_COLORMAP
285 		XFreeColors(display, cmap, &(MI_BLACK_PIXEL(mi)), 1, 0);
286 		XFreeColors(display, cmap, &(MI_WHITE_PIXEL(mi) ), 1, 0);
287 #endif
288 		XFreeColors(display, cmap, &(MI_BG_PIXEL(mi)), 1, 0);
289 		XFreeColors(display, cmap, &(MI_FG_PIXEL(mi)), 1, 0);
290 #ifndef COMPLIANT_COLORMAP
291 		if (retry) {
292 			fixColormap(mi, 64, 1.0,
293 				    mono, install, inroot, inwindow, verbose);
294 			return;
295 		}
296 #endif
297 		monoColormap(scr, MI_SCREENINFO(mi), foreground, background);
298 		MI_COLORMAP(mi) = cmap = DefaultColormapOfScreen(scr);
299 		return;
300 	}
301 	MI_COLORMAP(mi) = cmap;
302 	if ((install || fixed) && !inroot && MI_NPIXELS(mi) > 2) {
303 #if 0
304 		(void) XGetWindowAttributes(display, window, &xgwa);
305 		if (cmap != xgwa.colormap)
306 #endif
307 #if 1				/* Turn off to simulate fvwm and tvwm */
308 			setColormap(display, window, cmap, inwindow);
309 #endif
310 	}
311 #if 0
312 	else {
313 		/* white and black colors may not be right for GL modes so lets set them */
314 		MI_BLACK_PIXEL(mi) = BlackPixelOfScreen(scr);
315 		MI_WHITE_PIXEL(mi) = WhitePixelOfScreen(scr);
316 		/* foreground and background colors may not be right.... */
317 		BlackPixelOfScreen(scr) = MI_BLACK_PIXEL(mi);
318 		WhitePixelOfScreen(scr) = MI_WHITE_PIXEL(mi);
319 	}
320 #endif
321 }
322 
323 void
setColormap(Display * display,Window window,Colormap cmap,Bool inwindow)324 setColormap(Display * display, Window window, Colormap cmap, Bool inwindow)
325 {
326 	XSetWindowColormap(display, window, cmap);
327 	/* Now, here we have a problem.  When we are running full-screen, the
328 	   window's override_redirect attribute is on.  So, the window manager
329 	   never gets the ColormapNotify event that gets generated on the
330 	   above XSetWindowColormap() call, and does not So, a quick solution
331 	   is to install it ourselves.  The problem with this is that it
332 	   violates the ICCCM convention that only window managers should
333 	   install colormaps. Indeed, Fvwm _enforces_ this by immediately
334 	   un-doing any XInstallColormap() performed by a client (which is why
335 	   this does not work right under Fvwm). */
336 
337 	if (!inwindow) {
338 		XInstallColormap(display, cmap);
339 	}
340 }
341 
342 #if 0
343 /*-
344  * useableColors
345  */
346 int
347 preserveColors(unsigned long black, unsigned long white,
348 	       unsigned long bg, unsigned long fg)
349 {
350 	/* how many colours should we preserve (out of white, black, fg, bg)? */
351 	if (((bg == black) || (bg == white)) && ((fg == black) || (fg == white)))
352 		return 2;
353 	else if ((bg == black) || (fg == black) ||
354 		 (bg == white) || (fg == white) || (bg == fg))
355 		return 3;
356 	else
357 		return 4;
358 }
359 #endif
360 
361 #ifdef HAVE_XPM
362 void
reserveColors(ModeInfo * mi,Colormap cmap,unsigned long * black)363 reserveColors(ModeInfo * mi, Colormap cmap, unsigned long *black)
364 {
365 	Display    *display = MI_DISPLAY(mi);
366 	XColor      blackcolor, whitecolor;
367 
368 	blackcolor.flags = DoRed | DoGreen | DoBlue;
369 	blackcolor.pixel = MI_BLACK_PIXEL(mi);
370 	blackcolor.red = 0;
371 	blackcolor.green = 0;
372 	blackcolor.blue = 0;
373 	whitecolor.flags = DoRed | DoGreen | DoBlue;
374 	whitecolor.pixel = MI_WHITE_PIXEL(mi);
375 	whitecolor.red = 0xFFFF;
376 	whitecolor.green = 0xFFFF;
377 	whitecolor.blue = 0xFFFF;
378 
379 	/* If they fail what should I do? */
380 	(void) XAllocColor(display, cmap, &blackcolor);
381 	(void) XAllocColor(display, cmap, &whitecolor);
382 	*black = blackcolor.pixel;
383 
384 #if 0
385 	{
386 		XColor      bgcolor, fgcolor;
387 
388 		bgcolor.pixel = MI_BG_PIXEL(mi);
389 		fgcolor.pixel = MI_FG_PIXEL(mi);
390 		XQueryColor(display, cmap, &bgcolor);
391 		XQueryColor(display, cmap, &fgcolor);
392 		(void) XAllocColor(display, cmap, &bgcolor);
393 		(void) XAllocColor(display, cmap, &fgcolor);
394 	}
395 #endif
396 }
397 
398 #endif
399 
400 /* the remaining of this file was hacked from colors.c and hsv.c from
401  * xscreensaver
402  *
403  * xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz AT jwz.org>
404  *
405  * Permission to use, copy, modify, distribute, and sell this software and its
406  * documentation for any purpose is hereby granted without fee, provided that
407  * the above copyright notice appear in all copies and that both that
408  * copyright notice and this permission notice appear in supporting
409  * documentation.  No representations are made about the suitability of this
410  * software for any purpose.  It is provided "as is" without express or
411  * implied warranty.
412  *
413  * Modified for the use with xlockmore by Jouk Jansen <joukj AT hrem.nano.tudelft.nl>
414  * 12 June 1998
415  */
416 
417 /* This file contains some utility routines for randomly picking the colors
418    to hack the screen with.
419  */
420 
421 void
free_colors(Display * dpy,Colormap cmap,XColor * colors,int ncolors)422 free_colors(Display * dpy, Colormap cmap, XColor * colors, int ncolors)
423 {
424 	int         i;
425 
426 	if (ncolors > 0) {
427 		unsigned long *pixels;
428 
429 		if ((pixels = (unsigned long *) malloc(sizeof (unsigned long) *
430 				ncolors)) == NULL) {
431 			(void) fprintf(stderr, "could not free colors\n");
432 			return;
433 		}
434 
435 		for (i = 0; i < ncolors; i++)
436 			pixels[i] = colors[i].pixel;
437 		XFreeColors(dpy, cmap, pixels, ncolors, 0L);
438 		free(pixels);
439 	}
440 }
441 
442 
443 static void
allocate_writable_colors(Display * dpy,Colormap cmap,unsigned long * pixels,int * ncolorsP)444 allocate_writable_colors(Display * dpy, Colormap cmap,
445 			 unsigned long *pixels, int *ncolorsP)
446 {
447 	int         desired = *ncolorsP;
448 	int         got = 0;
449 	int         requested = desired;
450 	unsigned long *new_pixels = pixels;
451 
452 	*ncolorsP = 0;
453 	while (got < desired
454 	       && requested > 0) {
455 		if (desired - got < requested)
456 			requested = desired - got;
457 
458 		if (XAllocColorCells(dpy, cmap, False, 0, 0, new_pixels, requested)) {
459 			/* Got all the pixels we asked for. */
460 			new_pixels += requested;
461 			got += requested;
462 		} else {
463 			/* We didn't get all/any of the pixels we asked for.  This time, ask
464 			   for half as many.  (If we do get all that we ask for, we ask for
465 			   the same number again next time, so we only do O(log(n)) server
466 			   roundtrips.)
467 			 */
468 			requested = requested / 2;
469 		}
470 	}
471 	*ncolorsP += got;
472 }
473 
474 
475 
476 void
make_color_ramp(Display * dpy,Colormap cmap,int h1,double s1,double v1,int h2,double s2,double v2,XColor * colors,int * ncolorsP,Bool closed_p,Bool allocate_p,Bool writable_p)477 make_color_ramp(Display * dpy, Colormap cmap,
478 		int h1, double s1, double v1,	/* 0-360, 0-1.0, 0-1.0 */
479 		int h2, double s2, double v2,	/* 0-360, 0-1.0, 0-1.0 */
480 		XColor * colors, int *ncolorsP,
481 		Bool closed_p,
482 		Bool allocate_p,
483 		Bool writable_p)
484 {
485 	int         i;
486 	int         ncolors = *ncolorsP;
487 	double      dh, ds, dv;	/* deltas */
488 
489       AGAIN:
490 
491 	(void) memset(colors, 0, (*ncolorsP) * sizeof (*colors));
492 
493 	if (closed_p)
494 		ncolors = (ncolors / 2) + 1;
495 
496 	/* Note: unlike other routines in this module, this function assumes that
497 	   if h1 and h2 are more than 180 degrees apart, then the desired direction
498 	   is always from h1 to h2 (rather than the shorter path.)  make_uniform
499 	   depends on this.
500 	 */
501 	dh = ((double) h2 - (double) h1) / ncolors;
502 	ds = (s2 - s1) / ncolors;
503 	dv = (v2 - v1) / ncolors;
504 
505 	for (i = 0; i < ncolors; i++) {
506 		colors[i].flags = DoRed | DoGreen | DoBlue;
507 		hsv_to_rgb((int) (h1 + (i * dh)), (s1 + (i * ds)), (v1 + (i * dv)),
508 			   &colors[i].red, &colors[i].green, &colors[i].blue);
509 	}
510 
511 	if (closed_p)
512 		for (i = ncolors; i < *ncolorsP; i++)
513 			colors[i] = colors[(*ncolorsP) - i];
514 
515 	if (!allocate_p)
516 		return;
517 
518 	if (writable_p) {
519 		unsigned long *pixels;
520 
521 		if ((pixels = (unsigned long *) malloc(sizeof (unsigned long) *
522 				((*ncolorsP) + 1))) == NULL) {
523 			goto FAIL;
524 		}
525 
526 		/* allocate_writable_colors() won't do here, because we need exactly this
527 		   number of cells, or the color sequence we've chosen won't fit. */
528 		if (!XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP)) {
529 			free(pixels);
530 			goto FAIL;
531 		}
532 		for (i = 0; i < *ncolorsP; i++)
533 			colors[i].pixel = pixels[i];
534 		free(pixels);
535 
536 		XStoreColors(dpy, cmap, colors, *ncolorsP);
537 	} else {
538 		for (i = 0; i < *ncolorsP; i++) {
539 			XColor      color;
540 
541 			color = colors[i];
542 			if (XAllocColor(dpy, cmap, &color)) {
543 				colors[i].pixel = color.pixel;
544 			} else {
545 				free_colors(dpy, cmap, colors, i);
546 				goto FAIL;
547 			}
548 		}
549 	}
550 
551 	return;
552 
553       FAIL:
554 	/* we weren't able to allocate all the colors we wanted;
555 	   decrease the requested number and try again.
556 	 */
557 	ncolors = (ncolors > 170 ? ncolors - 20 :
558 		   ncolors > 100 ? ncolors - 10 :
559 		   ncolors > 75 ? ncolors - 5 :
560 		   ncolors > 25 ? ncolors - 3 :
561 		   ncolors > 10 ? ncolors - 2 :
562 		   ncolors > 2 ? ncolors - 1 :
563 		   0);
564 	*ncolorsP = ncolors;
565 	if (ncolors > 0)
566 		goto AGAIN;
567 }
568 
569 
570 #define MAXPOINTS 50		/* yeah, so I'm lazy */
571 
572 
573 static void
make_color_path(Display * dpy,Colormap cmap,int npoints,int * h,double * s,double * v,XColor * colors,int * ncolorsP,Bool allocate_p,Bool writable_p)574 make_color_path(Display * dpy, Colormap cmap,
575 		int npoints, int *h, double *s, double *v,
576 		XColor * colors, int *ncolorsP,
577 		Bool allocate_p,
578 		Bool writable_p)
579 {
580 	int         i, k;
581 	int         total_ncolors = *ncolorsP;
582 
583 	int         ncolors[MAXPOINTS];		/* number of pixels per edge */
584 	double      dh[MAXPOINTS];	/* distance between pixels, per edge (0 - 360.0) */
585 	double      ds[MAXPOINTS];	/* distance between pixels, per edge (0 - 1.0) */
586 	double      dv[MAXPOINTS];	/* distance between pixels, per edge (0 - 1.0) */
587 
588 	if (npoints == 0) {
589 		*ncolorsP = 0;
590 		return;
591 	} else if (npoints == 2) {	/* using make_color_ramp() will be faster */
592 		make_color_ramp(dpy, cmap,
593 				h[0], s[0], v[0], h[1], s[1], v[1],
594 				colors, ncolorsP,
595 				True,	/* closed_p */
596 				allocate_p, writable_p);
597 		return;
598 	} else if (npoints >= MAXPOINTS) {
599 		npoints = MAXPOINTS - 1;
600 	}
601       AGAIN:
602 
603 	{
604 		double      DH[MAXPOINTS];	/* Distance between H values in the shortest
605 
606 						   direction around the circle, that is, the
607 						   distance between 10 and 350 is 20.
608 						   (Range is 0 - 360.0.)
609 						 */
610 		double      edge[MAXPOINTS];	/* lengths of edges in unit HSV space. */
611 		double      ratio[MAXPOINTS];	/* proportions of the edges (total 1.0) */
612 		double      circum = 0;
613 		double      one_point_oh = 0;	/* (debug) */
614 
615 		for (i = 0; i < npoints; i++) {
616 			int         j = (i + 1) % npoints;
617 			double      d = ((double) (h[i] - h[j])) / 360;
618 
619 			if (d < 0)
620 				d = -d;
621 			if (d > 0.5)
622 				d = 0.5 - (d - 0.5);
623 			DH[i] = d;
624 		}
625 
626 		for (i = 0; i < npoints; i++) {
627 			int         j = (i + 1) % npoints;
628 
629 			edge[i] = sqrt((DH[i] * DH[j]) +
630 				       ((s[j] - s[i]) * (s[j] - s[i])) +
631 				       ((v[j] - v[i]) * (v[j] - v[i])));
632 			circum += edge[i];
633 		}
634 
635 #ifdef DEBUG
636 		(void) fprintf(stderr, "\ncolors:");
637 		for (i = 0; i < npoints; i++)
638 			(void) fprintf(stderr, " (%d, %.3f, %.3f)", h[i], s[i], v[i]);
639 		(void) fprintf(stderr, "\nlengths:");
640 		for (i = 0; i < npoints; i++)
641 			(void) fprintf(stderr, " %.3f", edge[i]);
642 #endif /* DEBUG */
643 
644 		if (circum < 0.0001)
645 			goto FAIL;
646 
647 		for (i = 0; i < npoints; i++) {
648 			ratio[i] = edge[i] / circum;
649 			one_point_oh += ratio[i];
650 		}
651 
652 #ifdef DEBUG
653 		(void) fprintf(stderr, "\nratios:");
654 		for (i = 0; i < npoints; i++)
655 			(void) fprintf(stderr, " %.3f", ratio[i]);
656 #endif /* DEBUG */
657 
658 		if (one_point_oh < 0.99999 || one_point_oh > 1.00001)
659 			abort();
660 
661 		/* space the colors evenly along the circumference -- that means that the
662 		   number of pixels on a edge is proportional to the length of that edge
663 		   (relative to the lengths of the other edges.)
664 		 */
665 		for (i = 0; i < npoints; i++)
666 			ncolors[i] = (int) (total_ncolors * ratio[i]);
667 
668 
669 #ifdef DEBUG
670 		(void) fprintf(stderr, "\npixels:");
671 		for (i = 0; i < npoints; i++)
672 			(void) fprintf(stderr, " %d", ncolors[i]);
673 		(void) fprintf(stderr, "  (%d)\n", total_ncolors);
674 #endif /* DEBUG */
675 
676 		for (i = 0; i < npoints; i++) {
677 			int         j = (i + 1) % npoints;
678 
679 			if (ncolors[i] > 0) {
680 				dh[i] = 360 * (DH[i] / ncolors[i]);
681 				ds[i] = (s[j] - s[i]) / ncolors[i];
682 				dv[i] = (v[j] - v[i]) / ncolors[i];
683 			}
684 		}
685 	}
686 
687 	(void) memset(colors, 0, (*ncolorsP) * sizeof (*colors));
688 
689 	k = 0;
690 	for (i = 0; i < npoints; i++) {
691 		int         distance, direction, j;
692 
693 		distance = h[(i + 1) % npoints] - h[i];
694 		direction = (distance >= 0 ? -1 : 1);
695 
696 		if (distance > 180)
697 			distance = 180 - (distance - 180);
698 		else if (distance < -180)
699 			distance = -(180 - ((-distance) - 180));
700 		else
701 			direction = -direction;
702 
703 #ifdef DEBUG
704 		(void) fprintf(stderr, "point %d: %3d %.2f %.2f\n",
705 			i, h[i], s[i], v[i]);
706 		(void) fprintf(stderr, "  h[i]=%d  dh[i]=%.2f  ncolors[i]=%d\n",
707 			h[i], dh[i], ncolors[i]);
708 #endif /* DEBUG */
709 		for (j = 0; j < ncolors[i]; j++, k++) {
710 			double      hh = (h[i] + (j * dh[i] * direction));
711 
712 			if (hh < 0)
713 				hh += 360;
714 			else if (hh > 360)
715 				hh -= 0;
716 			colors[k].flags = DoRed | DoGreen | DoBlue;
717 			hsv_to_rgb((int)
718 				   hh,
719 				   (s[i] + (j * ds[i])),
720 				   (v[i] + (j * dv[i])),
721 			  &colors[k].red, &colors[k].green, &colors[k].blue);
722 #ifdef DEBUG
723 			(void) fprintf(stderr, "point %d+%d: %.2f %.2f %.2f  %04X %04X %04X\n",
724 				i, j,
725 				hh,
726 				(s[i] + (j * ds[i])),
727 				(v[i] + (j * dv[i])),
728 			     colors[k].red, colors[k].green, colors[k].blue);
729 #endif /* DEBUG */
730 		}
731 	}
732 
733 	/* Floating-point round-off can make us decide to use fewer colors. */
734 	if (k < *ncolorsP) {
735 		*ncolorsP = k;
736 		if (k <= 0)
737 			return;
738 	}
739 	if (!allocate_p)
740 		return;
741 
742 	if (writable_p) {
743 		unsigned long *pixels = (unsigned long *)
744 		malloc(sizeof (unsigned long) * ((*ncolorsP) + 1));
745 
746 		/* allocate_writable_colors() won't do here, because we need exactly this
747 		   number of cells, or the color sequence we've chosen won't fit. */
748 		if (!XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP)) {
749 			free(pixels);
750 			goto FAIL;
751 		}
752 		for (i = 0; i < *ncolorsP; i++)
753 			colors[i].pixel = pixels[i];
754 		free(pixels);
755 
756 		XStoreColors(dpy, cmap, colors, *ncolorsP);
757 	} else {
758 		for (i = 0; i < *ncolorsP; i++) {
759 			XColor      color;
760 
761 			color = colors[i];
762 			if (XAllocColor(dpy, cmap, &color)) {
763 				colors[i].pixel = color.pixel;
764 			} else {
765 				free_colors(dpy, cmap, colors, i);
766 				goto FAIL;
767 			}
768 		}
769 	}
770 
771 	return;
772 
773       FAIL:
774 	/* we weren't able to allocate all the colors we wanted;
775 	   decrease the requested number and try again.
776 	 */
777 	total_ncolors = (total_ncolors > 170 ? total_ncolors - 20 :
778 			 total_ncolors > 100 ? total_ncolors - 10 :
779 			 total_ncolors > 75 ? total_ncolors - 5 :
780 			 total_ncolors > 25 ? total_ncolors - 3 :
781 			 total_ncolors > 10 ? total_ncolors - 2 :
782 			 total_ncolors > 2 ? total_ncolors - 1 :
783 			 0);
784 	*ncolorsP = total_ncolors;
785 	if (total_ncolors > 0)
786 		goto AGAIN;
787 }
788 
789 #if 0
790 void
791 make_color_loop(Display * dpy, Colormap cmap,
792 		int h0, double s0, double v0,	/* 0-360, 0-1.0, 0-1.0 */
793 		int h1, double s1, double v1,	/* 0-360, 0-1.0, 0-1.0 */
794 		int h2, double s2, double v2,	/* 0-360, 0-1.0, 0-1.0 */
795 		XColor * colors, int *ncolorsP,
796 		Bool allocate_p,
797 		Bool writable_p)
798 {
799 	int         h[3];
800 	double      s[3], v[3];
801 
802 	h[0] = h0;
803 	h[1] = h1;
804 	h[2] = h2;
805 	s[0] = s0;
806 	s[1] = s1;
807 	s[2] = s2;
808 	v[0] = v0;
809 	v[1] = v1;
810 	v[2] = v2;
811 	make_color_path(dpy, cmap,
812 			3, h, s, v,
813 			colors, ncolorsP,
814 			allocate_p, writable_p);
815 }
816 #endif
817 
818 static void
complain(int wanted_colors,int got_colors,Bool wanted_writable,Bool got_writable)819 complain(int wanted_colors, int got_colors,
820 	 Bool wanted_writable, Bool got_writable)
821 {
822 	if (wanted_writable && !got_writable)
823 		(void) fprintf(stderr,
824 		 "%s: wanted %d writable colors; got %d read-only colors.\n",
825 			ProgramName, wanted_colors, got_colors);
826 
827 	else if (wanted_colors > (got_colors + 10))
828 		/* don't bother complaining if we're within ten pixels. */
829 		(void) fprintf(stderr, "%s: wanted %d%s colors; got %d.\n",
830 		  ProgramName, wanted_colors, (got_writable ? " writable" : ""),
831 			got_colors);
832 }
833 
834 
835 void
make_smooth_colormap(ModeInfo * mi,Colormap cmap,XColor * colors,int * ncolorsP,Bool allocate_p,Bool * writable_pP)836 make_smooth_colormap(ModeInfo * mi, Colormap cmap,
837 		     XColor * colors, int *ncolorsP,
838 		     Bool allocate_p,
839 		     Bool * writable_pP)
840 {
841 	int         npoints;
842 	int         ncolors = *ncolorsP;
843 	Bool        wanted_writable = (allocate_p && writable_pP && *writable_pP);
844 	int         i;
845 	int         h[MAXPOINTS];
846 	double      s[MAXPOINTS];
847 	double      v[MAXPOINTS];
848 	double      total_s = 0;
849 	double      total_v = 0;
850 
851 	if (*ncolorsP <= 0)
852 		return;
853 
854 	{
855 		int         n = (int) (LRAND() % 20);
856 
857 		if (n <= 5)
858 			npoints = 2;	/* 30% of the time */
859 		else if (n <= 15)
860 			npoints = 3;	/* 50% of the time */
861 		else if (n <= 18)
862 			npoints = 4;	/* 15% of the time */
863 		else
864 			npoints = 5;	/*  5% of the time */
865 	}
866 
867       REPICK_ALL_COLORS:
868 	for (i = 0; i < npoints; i++) {
869 	      REPICK_THIS_COLOR:
870 		h[i] = (int) (LRAND() % 360);
871 		s[i] = LRAND() / MAXRAND;
872 		v[i] = 0.8 * LRAND() / MAXRAND + 0.2;
873 
874 		/* Make sure that no two adjacent colors are *too* close together.
875 		   If they are, try again.
876 		 */
877 		if (i > 0) {
878 			int         j = (i + 1 == npoints) ? 0 : (i - 1);
879 			double      hi = ((double) h[i]) / 360;
880 			double      hj = ((double) h[j]) / 360;
881 			double      dh = hj - hi;
882 			double      distance;
883 
884 			if (dh < 0)
885 				dh = -dh;
886 			if (dh > 0.5)
887 				dh = 0.5 - (dh - 0.5);
888 			distance = sqrt((dh * dh) +
889 					((s[j] - s[i]) * (s[j] - s[i])) +
890 					((v[j] - v[i]) * (v[j] - v[i])));
891 			if (distance < 0.2)
892 				goto REPICK_THIS_COLOR;
893 		}
894 		total_s += s[i];
895 		total_v += v[i];
896 	}
897 
898 	/* If the average saturation or intensity are too low, repick the colors,
899 	   so that we don't end up with a black-and-white or too-dark map.
900 	 */
901 	if (total_s / npoints < 0.2)
902 		goto REPICK_ALL_COLORS;
903 	if (total_v / npoints < 0.3)
904 		goto REPICK_ALL_COLORS;
905 
906 	/* If this visual doesn't support writable cells, don't bother trying.
907 	 */
908 	if (wanted_writable && !has_writable_cells(mi))
909 		*writable_pP = False;
910 
911       RETRY_NON_WRITABLE:
912 	make_color_path(MI_DISPLAY(mi), cmap, npoints, h, s, v, colors, &ncolors,
913 			allocate_p, (writable_pP && *writable_pP));
914 
915 	/* If we tried for writable cells and got none, try for non-writable. */
916 	if (allocate_p && *ncolorsP == 0 && *writable_pP) {
917 		*writable_pP = False;
918 		goto RETRY_NON_WRITABLE;
919 	}
920 	if (MI_IS_VERBOSE(mi) || MI_IS_DEBUG(mi))
921 		complain(*ncolorsP, ncolors, wanted_writable,
922 			 wanted_writable && *writable_pP);
923 
924 	*ncolorsP = ncolors;
925 }
926 
927 
928 void
make_uniform_colormap(ModeInfo * mi,Colormap cmap,XColor * colors,int * ncolorsP,Bool allocate_p,Bool * writable_pP)929 make_uniform_colormap(ModeInfo * mi, Colormap cmap,
930 		      XColor * colors, int *ncolorsP,
931 		      Bool allocate_p,
932 		      Bool * writable_pP)
933 {
934 	int         ncolors = *ncolorsP;
935 	Bool        wanted_writable = (allocate_p && writable_pP && *writable_pP);
936 
937 	double      S = ((double) (LRAND() % 34) + 66) / 100.0;		/* range 66%-100% */
938 	double      V = ((double) (LRAND() % 34) + 66) / 100.0;		/* range 66%-100% */
939 
940 	if (*ncolorsP <= 0)
941 		return;
942 
943 	/* If this visual doesn't support writable cells, don't bother trying. */
944 	if (wanted_writable && !has_writable_cells(mi))
945 		*writable_pP = False;
946 
947       RETRY_NON_WRITABLE:
948 	make_color_ramp(MI_DISPLAY(mi), cmap,
949 			0, S, V,
950 			359, S, V,
951 			colors, &ncolors,
952 			False, True, wanted_writable);
953 
954 	/* If we tried for writable cells and got none, try for non-writable. */
955 	if (allocate_p && *ncolorsP == 0 && writable_pP && *writable_pP) {
956 		ncolors = *ncolorsP;
957 		*writable_pP = False;
958 		goto RETRY_NON_WRITABLE;
959 	}
960 	if (MI_IS_VERBOSE(mi) || MI_IS_DEBUG(mi))
961 		complain(*ncolorsP, ncolors, wanted_writable,
962 			 wanted_writable && *writable_pP);
963 
964 	*ncolorsP = ncolors;
965 }
966 
967 
968 void
make_random_colormap(ModeInfo * mi,Colormap cmap,XColor * colors,int * ncolorsP,Bool bright_p,Bool allocate_p,Bool * writable_pP)969 make_random_colormap(ModeInfo * mi, Colormap cmap,
970 		     XColor * colors, int *ncolorsP,
971 		     Bool bright_p,
972 		     Bool allocate_p,
973 		     Bool * writable_pP)
974 {
975 	Bool        wanted_writable = (allocate_p && writable_pP && *writable_pP);
976 	int         ncolors = *ncolorsP;
977 	int         i;
978 
979 	if (*ncolorsP <= 0)
980 		return;
981 
982 	/* If this visual doesn't support writable cells, don't bother trying. */
983 	if (wanted_writable && !has_writable_cells(mi))
984 		*writable_pP = False;
985 
986 	for (i = 0; i < ncolors; i++) {
987 		colors[i].flags = DoRed | DoGreen | DoBlue;
988 		if (bright_p) {
989 			int         H = (int) LRAND() % 360;	/* range 0-360    */
990 			double      S = ((double) (LRAND() % 70) + 30) / 100.0;		/* range 30%-100% */
991 			double      V = ((double) (LRAND() % 34) + 66) / 100.0;		/* range 66%-100% */
992 
993 			hsv_to_rgb(H, S, V,
994 			  &colors[i].red, &colors[i].green, &colors[i].blue);
995 		} else {
996 			colors[i].red = (unsigned short) (LRAND() % 0xFFFF);
997 			colors[i].green = (unsigned short) (LRAND() % 0xFFFF);
998 			colors[i].blue = (unsigned short) (LRAND() % 0xFFFF);
999 		}
1000 	}
1001 
1002 	if (!allocate_p)
1003 		return;
1004 
1005       RETRY_NON_WRITABLE:
1006 	if (writable_pP && *writable_pP) {
1007 		unsigned long *pixels = (unsigned long *)
1008 		malloc(sizeof (unsigned long) * (ncolors + 1));
1009 
1010 		allocate_writable_colors(MI_DISPLAY(mi), cmap, pixels, &ncolors);
1011 		if (ncolors > 0)
1012 			for (i = 0; i < ncolors; i++)
1013 				colors[i].pixel = pixels[i];
1014 		free(pixels);
1015 		if (ncolors > 0)
1016 			XStoreColors(MI_DISPLAY(mi), cmap, colors, ncolors);
1017 	} else {
1018 		for (i = 0; i < ncolors; i++) {
1019 			XColor      color;
1020 
1021 			color = colors[i];
1022 			if (!XAllocColor(MI_DISPLAY(mi), cmap, &color))
1023 				break;
1024 			colors[i].pixel = color.pixel;
1025 		}
1026 		ncolors = i;
1027 	}
1028 
1029 	/* If we tried for writable cells and got none, try for non-writable. */
1030 	if (allocate_p && ncolors == 0 && writable_pP && *writable_pP) {
1031 		ncolors = *ncolorsP;
1032 		*writable_pP = False;
1033 		goto RETRY_NON_WRITABLE;
1034 	}
1035 	if (MI_IS_VERBOSE(mi) || MI_IS_DEBUG(mi))
1036 		complain(*ncolorsP, ncolors, wanted_writable,
1037 			 wanted_writable && *writable_pP);
1038 
1039 	*ncolorsP = ncolors;
1040 }
1041 
1042 
1043 void
rotate_colors(Display * dpy,Colormap cmap,XColor * colors,int ncolors,int distance)1044 rotate_colors(Display * dpy, Colormap cmap,
1045 	      XColor * colors, int ncolors, int distance)
1046 {
1047 	int         i;
1048 	XColor     *colors2;
1049 
1050 	if (ncolors < 2)
1051 		return;
1052 	colors2 = (XColor *) malloc(sizeof (XColor) * ncolors);
1053 	distance = distance % ncolors;
1054 	for (i = 0; i < ncolors; i++) {
1055 		int         j = i - distance;
1056 
1057 		if (j >= ncolors)
1058 			j -= ncolors;
1059 		if (j < 0)
1060 			j += ncolors;
1061 		colors2[i] = colors[j];
1062 		colors2[i].pixel = colors[i].pixel;
1063 	}
1064 	XStoreColors(dpy, cmap, colors2, ncolors);
1065 	XFlush(dpy);
1066 	(void) memcpy((char *) colors, colors2, sizeof (*colors) * ncolors);
1067 	free(colors2);
1068 }
1069 
1070 /* xscreensaver, Copyright (c) 1992, 1997 Jamie Zawinski <jwz AT jwz.org>
1071 
1072  * Permission to use, copy, modify, distribute, and sell this software and its
1073  * documentation for any purpose is hereby granted without fee, provided that
1074  * the above copyright notice appear in all copies and that both that
1075  * copyright notice and this permission notice appear in supporting
1076  * documentation.  No representations are made about the suitability of this
1077  * software for any purpose.  It is provided "as is" without express or
1078  * implied warranty.
1079  */
1080 
1081 /* This file contains some utility routines for randomly picking the colors
1082    to hack the screen with.
1083  */
1084 
1085 void
hsv_to_rgb(int h,double s,double v,unsigned short * r,unsigned short * g,unsigned short * b)1086 hsv_to_rgb(int h, double s, double v,
1087 	   unsigned short *r, unsigned short *g, unsigned short *b)
1088 {
1089 	double      H, S, V, R, G, B;
1090 	double      p1, p2, p3;
1091 	double      f;
1092 	int         i;
1093 
1094 	if (s < 0)
1095 		s = 0;
1096 	if (v < 0)
1097 		v = 0;
1098 	if (s > 1)
1099 		s = 1;
1100 	if (v > 1)
1101 		v = 1;
1102 
1103 	S = s;
1104 	V = v;
1105 	H = (h % 360) / 60.0;
1106 	i = (int) H;
1107 	f = H - i;
1108 	p1 = V * (1 - S);
1109 	p2 = V * (1 - (S * f));
1110 	p3 = V * (1 - (S * (1 - f)));
1111 	if (i == 0) {
1112 		R = V;
1113 		G = p3;
1114 		B = p1;
1115 	} else if (i == 1) {
1116 		R = p2;
1117 		G = V;
1118 		B = p1;
1119 	} else if (i == 2) {
1120 		R = p1;
1121 		G = V;
1122 		B = p3;
1123 	} else if (i == 3) {
1124 		R = p1;
1125 		G = p2;
1126 		B = V;
1127 	} else if (i == 4) {
1128 		R = p3;
1129 		G = p1;
1130 		B = V;
1131 	} else {
1132 		R = V;
1133 		G = p1;
1134 		B = p2;
1135 	}
1136 	*r = (short unsigned int) (R * 65535);
1137 	*g = (short unsigned int) (G * 65535);
1138 	*b = (short unsigned int) (B * 65535);
1139 }
1140 
1141 #if 0
1142 void
1143 rgb_to_hsv(unsigned short r, unsigned short g, unsigned short b,
1144 	   int *h, double *s, double *v)
1145 {
1146 	double      R, G, B, H, S, V;
1147 	double      cmax, cmin;
1148 	double      cmm;
1149 	int         imax;
1150 
1151 	R = ((double) r) / 65535.0;
1152 	G = ((double) g) / 65535.0;
1153 	B = ((double) b) / 65535.0;
1154 	cmax = R;
1155 	cmin = G;
1156 	imax = 1;
1157 	if (cmax < G) {
1158 		cmax = G;
1159 		cmin = R;
1160 		imax = 2;
1161 	}
1162 	if (cmax < B) {
1163 		cmax = B;
1164 		imax = 3;
1165 	}
1166 	if (cmin > B) {
1167 		cmin = B;
1168 	}
1169 	cmm = cmax - cmin;
1170 	V = cmax;
1171 	if (cmm == 0)
1172 		S = H = 0;
1173 	else {
1174 		S = cmm / cmax;
1175 		if (imax == 1)
1176 			H = (G - B) / cmm;
1177 		else if (imax == 2)
1178 			H = 2.0 + (B - R) / cmm;
1179 		else		/*if (imax == 3) */
1180 			H = 4.0 + (R - G) / cmm;
1181 		if (H < 0)
1182 			H += 6.0;
1183 	}
1184 	*h = (int) (H * 60.0);
1185 	*s = S;
1186 	*v = V;
1187 }
1188 #endif
1189 
1190 #ifndef WIN32
1191 static int
allocate_color_planes(Display * dpy,Colormap cmap,int nplanes,unsigned long * plane_masks,unsigned long * base_pixel_ret)1192 allocate_color_planes (Display *dpy, Colormap cmap,
1193 		       int nplanes, unsigned long *plane_masks,
1194 		       unsigned long *base_pixel_ret)
1195 {
1196   while (nplanes > 1 &&
1197 	 !XAllocColorCells (dpy, cmap, False, plane_masks, nplanes,
1198 			    base_pixel_ret, 1))
1199     nplanes--;
1200 
1201   return nplanes;
1202 }
1203 
1204 static void
merge_colors(int argc,XColor ** argv,XColor * into_color,int mask,Bool additive_p)1205 merge_colors (int argc, XColor **argv, XColor *into_color, int mask,
1206 	      Bool additive_p)
1207 {
1208   int j;
1209   *into_color = *argv [0];
1210   into_color->pixel |= mask;
1211 
1212   for (j = 1; j < argc; j++)
1213     {
1214 # define SHORT_INC(x,y) (x = ((((x)+(y)) > 0xFFFF) ? 0xFFFF : ((x)+(y))))
1215 # define SHORT_DEC(x,y) (x = ((((x)-(y)) < 0)      ? 0      : ((x)-(y))))
1216       if (additive_p)
1217 	{
1218 	  SHORT_INC (into_color->red,   argv[j]->red);
1219 	  SHORT_INC (into_color->green, argv[j]->green);
1220 	  SHORT_INC (into_color->blue,  argv[j]->blue);
1221 	}
1222       else
1223 	{
1224 	  SHORT_DEC (into_color->red,   argv[j]->red);
1225 	  SHORT_DEC (into_color->green, argv[j]->green);
1226 	  SHORT_DEC (into_color->blue,  argv[j]->blue);
1227 	}
1228 # undef SHORT_INC
1229 # undef SHORT_DEC
1230     }
1231 }
1232 
1233 static int
i_exp(int i,int j)1234 i_exp (int i, int j)
1235 {
1236   int k = 1;
1237   while (j--) k *= i;
1238   return k;
1239 }
1240 
1241 static void
permute_colors(XColor * pcolors,XColor * colors,int count,unsigned long * plane_masks,Bool additive_p)1242 permute_colors (XColor *pcolors, XColor *colors,
1243 		int count,
1244 		unsigned long *plane_masks,
1245 		Bool additive_p)
1246 {
1247   int out = 0;
1248   int max = i_exp (2, count);
1249   if (count > 31) abort ();
1250   for (out = 1; out < max; out++)
1251     {
1252       XColor *argv [32];
1253       int this_mask = 0;
1254       int argc = 0;
1255       int bit;
1256       for (bit = 0; bit < 32; bit++)
1257 	if (out & (1<<bit))
1258 	  {
1259 	    argv [argc++] = &pcolors [bit];
1260 	    this_mask |= plane_masks [bit];
1261 	  }
1262       merge_colors (argc, argv, &colors [out-1], this_mask, additive_p);
1263     }
1264 }
1265 
1266 static void
initialize_transparency_colormap(Display * dpy,Colormap cmap,int nplanes,unsigned long base_pixel,unsigned long * plane_masks,XColor * colors,Bool additive_p,ModeInfo * mi)1267 initialize_transparency_colormap (Display *dpy, Colormap cmap,
1268 				  int nplanes,
1269 				  unsigned long base_pixel,
1270 				  unsigned long *plane_masks,
1271 				  XColor *colors,
1272 				  Bool additive_p , ModeInfo* mi )
1273 {
1274   int i;
1275   int total_colors = i_exp (2, nplanes);
1276   XColor *all_colors = (XColor *) calloc (total_colors, sizeof (XColor));
1277 
1278   for (i = 0; i < nplanes; i++)
1279     colors[i].pixel = base_pixel | plane_masks [i];
1280   permute_colors (colors, all_colors, nplanes, plane_masks, additive_p);
1281 
1282   /* clone the default background of the window into our "base" pixel */
1283   all_colors [total_colors - 1].pixel = MI_BLACK_PIXEL( mi );
1284   XQueryColor (dpy, cmap, &all_colors [total_colors - 1]);
1285   all_colors [total_colors - 1].pixel = base_pixel;
1286 
1287   for (i = 0; i < total_colors; i++)
1288     all_colors[i].flags = DoRed|DoGreen|DoBlue;
1289   XStoreColors (dpy, cmap, all_colors, total_colors);
1290   XFree ((XPointer) all_colors);
1291 }
1292 #endif
1293 
1294 int
screen_number(Screen * screen)1295 screen_number (Screen *screen)
1296 {
1297 #ifndef WIN32
1298   Display *dpy = DisplayOfScreen (screen);
1299   int i;
1300   for (i = 0; i < ScreenCount (dpy); i++)
1301     if (ScreenOfDisplay (dpy, i) == screen)
1302       return i;
1303 #endif
1304   return 0;
1305 }
1306 
1307 
1308 int
visual_depth(Screen * screen,Visual * visual)1309 visual_depth (Screen *screen, Visual *visual)
1310 {
1311 #ifdef WIN32
1312   return 8;
1313 #else
1314   Display *dpy = DisplayOfScreen (screen);
1315   XVisualInfo vi_in, *vi_out;
1316   int out_count, d;
1317   vi_in.screen = screen_number (screen);
1318   vi_in.visualid = XVisualIDFromVisual (visual);
1319   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
1320 			   &vi_in, &out_count);
1321   if (! vi_out) abort ();
1322   d = vi_out [0].depth;
1323   XFree ((char *) vi_out);
1324   return d;
1325 #endif
1326 }
1327 
1328 
1329 /* You very probably don't want to be using this.
1330    Pixmap depth doesn't refer to the depths of pixmaps, but rather, to
1331    the depth of protocol-level on-the-wire pixmap data, that is, XImages.
1332    To get this info, you should be looking at XImage->bits_per_pixel
1333    instead.  (And allocating the data for your XImage structures by
1334    multiplying ximage->bytes_per_line by ximage->height.)
1335 
1336    Still, it can be useful to know bits_per_pixel before the XImage exists.
1337 
1338    XCreateImage calls _XGetBitsPerPixel to figure this out, but that function
1339    is private to Xlib.
1340 
1341    For some reason, _XGetBitsPerPixel tries a hard-coded list of depths if
1342    it doesn't find a matching pixmap format, but I (Dave Odell) couldn't
1343    find any justification for this in the X11 spec. And the XFree86 CVS
1344    repository doesn't quite go back far enough to shed any light on what
1345    the deal is with that.
1346    http://cvsweb.xfree86.org/cvsweb/xc/lib/X11/ImUtil.c
1347 
1348    The hard-coded list apparently was added between X11R5 and X11R6.
1349    See <ftp://ftp.x.org/pub/>.
1350  */
1351 int
visual_pixmap_depth(Screen * screen,Visual * visual)1352 visual_pixmap_depth (Screen *screen, Visual *visual)
1353 {
1354 #ifdef WIN32
1355   return 1; /* XApi.c XPutImage only does bitmaps. */
1356 #else
1357   Display *dpy = DisplayOfScreen (screen);
1358   int vdepth = visual_depth (screen, visual);
1359   int pdepth = vdepth;
1360   int i, pfvc = 0;
1361   XPixmapFormatValues *pfv = XListPixmapFormats (dpy, &pfvc);
1362 
1363   /* Return the first matching depth in the pixmap formats.  If there are no
1364      matching pixmap formats (which shouldn't be able to happen at all) then
1365      return the visual depth instead. */
1366   for (i = 0; i < pfvc; i++)
1367     if (pfv[i].depth == vdepth)
1368       {
1369 	pdepth = pfv[i].bits_per_pixel;
1370 	break;
1371       }
1372   if (pfv)
1373     XFree (pfv);
1374   return pdepth;
1375 #endif
1376 }
1377 
1378 
1379 Bool
allocate_alpha_colors(Screen * screen,Visual * visual,Colormap cmap,int * nplanesP,Bool additive_p,unsigned long ** plane_masks,unsigned long * base_pixelP,ModeInfo * mi)1380 allocate_alpha_colors (Screen *screen, Visual *visual, Colormap cmap,
1381 		       int *nplanesP, Bool additive_p,
1382 		       unsigned long **plane_masks,
1383 		       unsigned long *base_pixelP , ModeInfo* mi)
1384 {
1385 #ifdef WIN32
1386   return False;
1387 #else
1388   Display *dpy = DisplayOfScreen (screen);
1389   XColor *colors;
1390   int nplanes = *nplanesP;
1391   int i;
1392 
1393   if (!has_writable_cells (mi))
1394     cmap = 0;
1395 
1396   if (!cmap)            /* A TrueColor visual, or similar. */
1397     {
1398       int depth = visual_depth (screen, visual);
1399       unsigned long masks;
1400       XVisualInfo vi_in, *vi_out;
1401 
1402       /* Find out which bits the R, G, and B components actually occupy
1403          on this visual. */
1404       vi_in.screen = screen_number (screen);
1405       vi_in.visualid = XVisualIDFromVisual (visual);
1406       vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
1407                                &vi_in, &i);
1408       if (! vi_out) return False;
1409       masks = vi_out[0].red_mask | vi_out[0].green_mask | vi_out[0].blue_mask;
1410       XFree ((char *) vi_out);
1411 
1412       if (nplanes > depth)
1413         nplanes = depth;
1414       *nplanesP = nplanes;
1415       *base_pixelP = 0;
1416       *plane_masks = (unsigned long *) calloc(sizeof(unsigned long), nplanes);
1417 
1418       /* Pick the planar values randomly, but constrain them to fall within
1419          the bit positions of the R, G, and B fields. */
1420       for (i = 0; i < nplanes; i++)
1421         (*plane_masks)[i] = LRAND() & masks;
1422 
1423     }
1424   else                  /* A PseudoColor visual, or similar. */
1425     {
1426       if (nplanes > 31) nplanes = 31;
1427       *plane_masks = (unsigned long *) malloc(sizeof(unsigned long) * nplanes);
1428 
1429       nplanes = allocate_color_planes (dpy, cmap, nplanes, *plane_masks,
1430 				   base_pixelP);
1431       *nplanesP = nplanes;
1432 
1433       if (nplanes <= 1)
1434         {
1435           free(*plane_masks);
1436           *plane_masks = 0;
1437           return False;
1438         }
1439 
1440       colors = (XColor *) calloc (nplanes, sizeof (XColor));
1441       for (i = 0; i < nplanes; i++)
1442         {
1443           /* pick the base colors. If we are in subtractive mode, pick higher
1444              intensities. */
1445           hsv_to_rgb (NRAND( 360 ),
1446                       NRAND( 100000 ) / 100000.0 ,
1447                       NRAND( 100000 ) / 200000.0 + (additive_p ? 0.2 : 0.5),
1448                       &colors[i].red,
1449                       &colors[i].green,
1450                       &colors[i].blue);
1451         }
1452       initialize_transparency_colormap (dpy, cmap, nplanes,
1453                                         *base_pixelP, *plane_masks, colors,
1454                                         additive_p , mi );
1455       XFree ((XPointer) colors);
1456     }
1457   return True;
1458 #endif
1459 }
1460