1 /* WMGlobe 1.3 -  All the Earth on a WMaker Icon
2  * mycontext.c - an adaptation of wrlib for use in wmglobe
3  * initial source taken in WindowMaker-0.20.3/wrlib :
4  */
5 /* context.c - X context management
6  *  Raster graphics library
7  *
8  *  Copyright (c) 1997 Alfredo K. Kojima
9  *
10  *  This library is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU Library General Public
12  *  License as published by the Free Software Foundation; either
13  *  version 2 of the License, or (at your option) any later version.
14  *
15  *  This library is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  Library General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Library General Public
21  *  License along with this library; if not, write to the Free
22  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24 
25 /*
26  * #include <config.h>
27  */
28 #include "wmglobe.h"
29 
30 /*
31  * #include <X11/Xlib.h>
32  * #include <X11/Xutil.h>
33  * #include <X11/Xatom.h>
34  *
35  * #include <stdio.h>
36  * #include <stdlib.h>
37  * #include <string.h>
38  * #include <assert.h>
39  *
40  * #include <math.h>
41  *
42  * #include "wraster.h"
43  */
44 
45 static Bool bestContext(Display * dpy, int screen_number,
46 			RContext * context);
47 
48 static RContextAttributes DEFAULT_CONTEXT_ATTRIBS = {
49     RC_DefaultVisual,		/* flags */
50     0,				/* render_mode */
51     3,				/* colors_per_channel */
52     0,
53     0,
54     0,
55     0,
56     0				/* NO use_shared_memory */
57 };
58 
59 
allocatePseudoColor(RContext * ctx)60 static XColor *allocatePseudoColor(RContext * ctx)
61 {
62     XColor *colors;
63     XColor avcolors[256];
64     int avncolors;
65     int i, ncolors, r, g, b;
66     int retries;
67     int cpc = ctx->attribs->colors_per_channel;
68 
69     ncolors = cpc * cpc * cpc;
70 
71     if (ncolors > (1 << ctx->depth)) {
72 	/* reduce colormap size */
73 	cpc = ctx->attribs->colors_per_channel =
74 	    1 << ((int) ctx->depth / 3);
75 	ncolors = cpc * cpc * cpc;
76     }
77     assert(cpc >= 2 && ncolors <= (1 << ctx->depth));
78 
79     colors = malloc(sizeof(XColor) * ncolors);
80     if (!colors) {
81 	RErrorCode = RERR_NOMEMORY;
82 	return NULL;
83     }
84     i = 0;
85 
86     if ((ctx->attribs->flags & RC_GammaCorrection)
87 	&& ctx->attribs->rgamma > 0 && ctx->attribs->ggamma > 0
88 	&& ctx->attribs->bgamma > 0) {
89 	double rg, gg, bg;
90 	double tmp;
91 
92 	/* do gamma correction */
93 	rg = 1.0 / ctx->attribs->rgamma;
94 	gg = 1.0 / ctx->attribs->ggamma;
95 	bg = 1.0 / ctx->attribs->bgamma;
96 	for (r = 0; r < cpc; r++) {
97 	    for (g = 0; g < cpc; g++) {
98 		for (b = 0; b < cpc; b++) {
99 		    colors[i].red = (r * 0xffff) / (cpc - 1);
100 		    colors[i].green = (g * 0xffff) / (cpc - 1);
101 		    colors[i].blue = (b * 0xffff) / (cpc - 1);
102 		    colors[i].flags = DoRed | DoGreen | DoBlue;
103 
104 		    tmp = (double) colors[i].red / 65536.0;
105 		    colors[i].red =
106 			(unsigned short) (65536.0 * pow(tmp, rg));
107 
108 		    tmp = (double) colors[i].green / 65536.0;
109 		    colors[i].green =
110 			(unsigned short) (65536.0 * pow(tmp, gg));
111 
112 		    tmp = (double) colors[i].blue / 65536.0;
113 		    colors[i].blue =
114 			(unsigned short) (65536.0 * pow(tmp, bg));
115 
116 		    i++;
117 		}
118 	    }
119 	}
120 
121     } else {
122 	for (r = 0; r < cpc; r++) {
123 	    for (g = 0; g < cpc; g++) {
124 		for (b = 0; b < cpc; b++) {
125 		    colors[i].red = (r * 0xffff) / (cpc - 1);
126 		    colors[i].green = (g * 0xffff) / (cpc - 1);
127 		    colors[i].blue = (b * 0xffff) / (cpc - 1);
128 		    colors[i].flags = DoRed | DoGreen | DoBlue;
129 		    i++;
130 		}
131 	    }
132 	}
133     }
134     /* try to allocate the colors */
135     for (i = 0; i < ncolors; i++) {
136 	if (!XAllocColor(ctx->dpy, ctx->cmap, &(colors[i]))) {
137 	    colors[i].flags = 0;	/* failed */
138 	} else {
139 	    colors[i].flags = DoRed | DoGreen | DoBlue;
140 	}
141     }
142     /* try to allocate close values for the colors that couldn't
143      * be allocated before */
144     avncolors = (1 << ctx->depth > 256 ? 256 : 1 << ctx->depth);
145     for (i = 0; i < avncolors; i++)
146 	avcolors[i].pixel = i;
147 
148     XQueryColors(ctx->dpy, ctx->cmap, avcolors, avncolors);
149 
150     for (i = 0; i < ncolors; i++) {
151 	if (colors[i].flags == 0) {
152 	    int j;
153 	    unsigned long cdiff = 0xffffffff, diff;
154 	    unsigned long closest = 0;
155 
156 	    retries = 2;
157 
158 	    while (retries--) {
159 		/* find closest color */
160 		for (j = 0; j < avncolors; j++) {
161 		    r = (colors[i].red - avcolors[i].red) >> 8;
162 		    g = (colors[i].green - avcolors[i].green) >> 8;
163 		    b = (colors[i].blue - avcolors[i].blue) >> 8;
164 		    diff = r * r + g * g + b * b;
165 		    if (diff < cdiff) {
166 			cdiff = diff;
167 			closest = j;
168 		    }
169 		}
170 		/* allocate closest color found */
171 		colors[i].red = avcolors[closest].red;
172 		colors[i].green = avcolors[closest].green;
173 		colors[i].blue = avcolors[closest].blue;
174 		if (XAllocColor(ctx->dpy, ctx->cmap, &colors[i])) {
175 		    colors[i].flags = DoRed | DoGreen | DoBlue;
176 		    break;	/* succeeded, don't need to retry */
177 		}
178 #ifdef DEBUG
179 		printf("close color allocation failed. Retrying...\n");
180 #endif
181 	    }
182 	}
183     }
184     return colors;
185 }
186 
187 
allocateGrayScale(RContext * ctx)188 static XColor *allocateGrayScale(RContext * ctx)
189 {
190     XColor *colors;
191     XColor avcolors[256];
192     int avncolors;
193     int i, ncolors, r, g, b;
194     int retries;
195     int cpc = ctx->attribs->colors_per_channel;
196 
197     ncolors = cpc * cpc * cpc;
198 
199     if (ctx->vclass == StaticGray) {
200 	/* we might as well use all grays */
201 	ncolors = 1 << ctx->depth;
202     } else {
203 	if (ncolors > (1 << ctx->depth)) {
204 	    /* reduce colormap size */
205 	    cpc = ctx->attribs->colors_per_channel =
206 		1 << ((int) ctx->depth / 3);
207 	    ncolors = cpc * cpc * cpc;
208 	}
209 	assert(cpc >= 2 && ncolors <= (1 << ctx->depth));
210     }
211 
212     if (ncolors >= 256 && ctx->vclass == StaticGray) {
213 	/* don't need dithering for 256 levels of gray in StaticGray visual */
214 	ctx->attribs->render_mode = RBestMatchRendering;
215     }
216     colors = malloc(sizeof(XColor) * ncolors);
217     if (!colors) {
218 	RErrorCode = RERR_NOMEMORY;
219 	return False;
220     }
221     for (i = 0; i < ncolors; i++) {
222 	colors[i].red = (i * 0xffff) / (ncolors - 1);
223 	colors[i].green = (i * 0xffff) / (ncolors - 1);
224 	colors[i].blue = (i * 0xffff) / (ncolors - 1);
225 	colors[i].flags = DoRed | DoGreen | DoBlue;
226     }
227     /* try to allocate the colors */
228     for (i = 0; i < ncolors; i++) {
229 #ifdef DEBUG
230 	printf("trying:%x,%x,%x\n", colors[i].red, colors[i].green,
231 	       colors[i].blue);
232 #endif
233 	if (!XAllocColor(ctx->dpy, ctx->cmap, &(colors[i]))) {
234 	    colors[i].flags = 0;	/* failed */
235 #ifdef DEBUG
236 	    printf("failed:%x,%x,%x\n", colors[i].red, colors[i].green,
237 		   colors[i].blue);
238 #endif
239 	} else {
240 	    colors[i].flags = DoRed | DoGreen | DoBlue;
241 #ifdef DEBUG
242 	    printf("success:%x,%x,%x\n", colors[i].red, colors[i].green,
243 		   colors[i].blue);
244 #endif
245 	}
246     }
247     /* try to allocate close values for the colors that couldn't
248      * be allocated before */
249     avncolors = (1 << ctx->depth > 256 ? 256 : 1 << ctx->depth);
250     for (i = 0; i < avncolors; i++)
251 	avcolors[i].pixel = i;
252 
253     XQueryColors(ctx->dpy, ctx->cmap, avcolors, avncolors);
254 
255     for (i = 0; i < ncolors; i++) {
256 	if (colors[i].flags == 0) {
257 	    int j;
258 	    unsigned long cdiff = 0xffffffff, diff;
259 	    unsigned long closest = 0;
260 
261 	    retries = 2;
262 
263 	    while (retries--) {
264 		/* find closest color */
265 		for (j = 0; j < avncolors; j++) {
266 		    r = (colors[i].red - avcolors[i].red) >> 8;
267 		    g = (colors[i].green - avcolors[i].green) >> 8;
268 		    b = (colors[i].blue - avcolors[i].blue) >> 8;
269 		    diff = r * r + g * g + b * b;
270 		    if (diff < cdiff) {
271 			cdiff = diff;
272 			closest = j;
273 		    }
274 		}
275 		/* allocate closest color found */
276 #ifdef DEBUG
277 		printf("best match:%x,%x,%x => %x,%x,%x\n", colors[i].red,
278 		       colors[i].green, colors[i].blue,
279 		       avcolors[closest].red, avcolors[closest].green,
280 		       avcolors[closest].blue);
281 #endif
282 		colors[i].red = avcolors[closest].red;
283 		colors[i].green = avcolors[closest].green;
284 		colors[i].blue = avcolors[closest].blue;
285 		if (XAllocColor(ctx->dpy, ctx->cmap, &colors[i])) {
286 		    colors[i].flags = DoRed | DoGreen | DoBlue;
287 		    break;	/* succeeded, don't need to retry */
288 		}
289 #ifdef DEBUG
290 		printf("close color allocation failed. Retrying...\n");
291 #endif
292 	    }
293 	}
294     }
295     return colors;
296 }
297 
298 
mygetenv(char * var,int scr)299 static char *mygetenv(char *var, int scr)
300 {
301     char *p;
302     char varname[64];
303 
304     sprintf(varname, "%s%i", var, scr);
305     p = getenv(varname);
306     if (!p) {
307 	p = getenv(var);
308     }
309     return p;
310 }
311 
312 
gatherconfig(RContext * context,int screen_n)313 static void gatherconfig(RContext * context, int screen_n)
314 {
315     char *ptr;
316 
317     ptr = mygetenv("WRASTER_GAMMA", screen_n);
318     if (ptr) {
319 	float g1, g2, g3;
320 	if (sscanf(ptr, "%f/%f/%f", &g1, &g2, &g3) != 3
321 	    || g1 <= 0.0 || g2 <= 0.0 || g3 <= 0.0) {
322 	    printf("wrlib: invalid value(s) for gamma correction \"%s\"\n",
323 		   ptr);
324 	} else {
325 	    context->attribs->flags |= RC_GammaCorrection;
326 	    context->attribs->rgamma = g1;
327 	    context->attribs->ggamma = g2;
328 	    context->attribs->bgamma = g3;
329 	}
330     }
331     ptr = mygetenv("WRASTER_COLOR_RESOLUTION", screen_n);
332     if (ptr) {
333 	int i;
334 	if (sscanf(ptr, "%d", &i) != 1 || i < 2 || i > 6) {
335 	    printf("wrlib: invalid value for color resolution \"%s\"\n",
336 		   ptr);
337 	} else {
338 	    context->attribs->flags |= RC_ColorsPerChannel;
339 	    context->attribs->colors_per_channel = i;
340 	}
341     }
342 }
343 
344 
getColormap(RContext * context,int screen_number)345 static void getColormap(RContext * context, int screen_number)
346 {
347     Colormap cmap = None;
348     XStandardColormap *cmaps;
349     int ncmaps, i;
350 
351     if (XGetRGBColormaps(context->dpy,
352 			 RootWindow(context->dpy, screen_number),
353 			 &cmaps, &ncmaps, XA_RGB_DEFAULT_MAP)) {
354 	for (i = 0; i < ncmaps; ++i) {
355 	    if (cmaps[i].visualid == context->visual->visualid) {
356 		puts("ACHOU");
357 		cmap = cmaps[i].colormap;
358 		break;
359 	    }
360 	}
361 	XFree(cmaps);
362     }
363     if (cmap == None) {
364 	XColor color;
365 
366 	cmap = XCreateColormap(context->dpy,
367 			       RootWindow(context->dpy, screen_number),
368 			       context->visual, AllocNone);
369 
370 	color.red = color.green = color.blue = 0;
371 	XAllocColor(context->dpy, cmap, &color);
372 	context->black = color.pixel;
373 
374 	color.red = color.green = color.blue = 0xffff;
375 	XAllocColor(context->dpy, cmap, &color);
376 	context->white = color.pixel;
377 
378     }
379     context->cmap = cmap;
380 }
381 
382 
count_offset(unsigned long mask)383 static int count_offset(unsigned long mask)
384 {
385     int i;
386 
387     i = 0;
388     while ((mask & 1) == 0) {
389 	i++;
390 	mask = mask >> 1;
391     }
392     return i;
393 }
394 
395 
myRCreateContext(Display * dpy,int screen_number,RContextAttributes * attribs)396 RContext *myRCreateContext(Display * dpy, int screen_number,
397 			   RContextAttributes * attribs)
398 {
399     RContext *context;
400     XGCValues gcv;
401 
402 
403     context = malloc(sizeof(RContext));
404     if (!context) {
405 	RErrorCode = RERR_NOMEMORY;
406 	return NULL;
407     }
408     memset(context, 0, sizeof(RContext));
409 
410     context->dpy = dpy;
411 
412     context->screen_number = screen_number;
413 
414     context->attribs = malloc(sizeof(RContextAttributes));
415     if (!context->attribs) {
416 	free(context);
417 	RErrorCode = RERR_NOMEMORY;
418 	return NULL;
419     }
420     if (!attribs)
421 	*context->attribs = DEFAULT_CONTEXT_ATTRIBS;
422     else
423 	*context->attribs = *attribs;
424 
425     /* get configuration from environment variables */
426     gatherconfig(context, screen_number);
427 
428     if ((context->attribs->flags & RC_VisualID)) {
429 	XVisualInfo *vinfo, templ;
430 	int nret;
431 
432 	templ.screen = screen_number;
433 	templ.visualid = context->attribs->visualid;
434 	vinfo =
435 	    XGetVisualInfo(context->dpy, VisualIDMask | VisualScreenMask,
436 			   &templ, &nret);
437 	if (!vinfo || nret == 0) {
438 	    free(context);
439 	    RErrorCode = RERR_BADVISUALID;
440 	    return NULL;
441 	}
442 	if (vinfo[0].visual == DefaultVisual(dpy, screen_number)) {
443 	    context->attribs->flags |= RC_DefaultVisual;
444 	} else {
445 	    XSetWindowAttributes attr;
446 	    unsigned long mask;
447 
448 	    context->visual = vinfo[0].visual;
449 	    context->depth = vinfo[0].depth;
450 	    context->vclass = vinfo[0].class;
451 	    getColormap(context, screen_number);
452 	    attr.colormap = context->cmap;
453 	    attr.override_redirect = True;
454 	    attr.border_pixel = 0;
455 	    attr.background_pixel = 0;
456 	    mask =
457 		CWBorderPixel | CWColormap | CWOverrideRedirect |
458 		CWBackPixel;
459 	    context->drawable =
460 		XCreateWindow(dpy, RootWindow(dpy, screen_number), 1, 1, 1,
461 			      1, 0, context->depth, CopyFromParent,
462 			      context->visual, mask, &attr);
463 	    /*          XSetWindowColormap(dpy, context->drawable, attr.colormap); */
464 	}
465 	XFree(vinfo);
466     }
467     /* use default */
468     if (!context->visual) {
469 	if ((context->attribs->flags & RC_DefaultVisual)
470 	    || !bestContext(dpy, screen_number, context)) {
471 	    context->visual = DefaultVisual(dpy, screen_number);
472 	    context->depth = DefaultDepth(dpy, screen_number);
473 	    context->cmap = DefaultColormap(dpy, screen_number);
474 	    context->drawable = RootWindow(dpy, screen_number);
475 	    context->black = BlackPixel(dpy, screen_number);
476 	    context->white = WhitePixel(dpy, screen_number);
477 	    context->vclass = context->visual->class;
478 	}
479     }
480     gcv.function = GXcopy;
481     gcv.graphics_exposures = False;
482     context->copy_gc = XCreateGC(dpy, context->drawable, GCFunction
483 				 | GCGraphicsExposures, &gcv);
484 
485     if (context->vclass == PseudoColor || context->vclass == StaticColor) {
486 	context->colors = allocatePseudoColor(context);
487 	if (!context->colors) {
488 	    return NULL;
489 	}
490     } else if (context->vclass == GrayScale
491 	       || context->vclass == StaticGray) {
492 	context->colors = allocateGrayScale(context);
493 	if (!context->colors) {
494 	    return NULL;
495 	}
496     } else if (context->vclass == TrueColor) {
497 	/* calc offsets to create a TrueColor pixel */
498 	context->red_offset = count_offset(context->visual->red_mask);
499 	context->green_offset = count_offset(context->visual->green_mask);
500 	context->blue_offset = count_offset(context->visual->blue_mask);
501 	/* disable dithering on 24 bits visuals */
502 	if (context->depth >= 24)
503 	    context->attribs->render_mode = RBestMatchRendering;
504     }
505     /* check avaiability of MIT-SHM */
506 
507     return context;
508 }
509 
510 
511 static Bool
bestContext(Display * dpy,int screen_number,RContext * context)512 bestContext(Display * dpy, int screen_number, RContext * context)
513 {
514     XVisualInfo *vinfo = NULL, rvinfo;
515     int best = -1, numvis, i;
516     long flags;
517     XSetWindowAttributes attr;
518 
519     rvinfo.class = TrueColor;
520     rvinfo.screen = screen_number;
521     flags = VisualClassMask | VisualScreenMask;
522 
523     vinfo = XGetVisualInfo(dpy, flags, &rvinfo, &numvis);
524     if (vinfo) {		/* look for a TrueColor, 24-bit or more (pref 24) */
525 	for (i = numvis - 1, best = -1; i >= 0; i--) {
526 	    if (vinfo[i].depth == 24)
527 		best = i;
528 	    else if (vinfo[i].depth > 24 && best < 0)
529 		best = i;
530 	}
531     }
532 #if 0
533     if (best == -1) {		/* look for a DirectColor, 24-bit or more (pref 24) */
534 	rvinfo.class = DirectColor;
535 	if (vinfo)
536 	    XFree((char *) vinfo);
537 	vinfo = XGetVisualInfo(dpy, flags, &rvinfo, &numvis);
538 	if (vinfo) {
539 	    for (i = 0, best = -1; i < numvis; i++) {
540 		if (vinfo[i].depth == 24)
541 		    best = i;
542 		else if (vinfo[i].depth > 24 && best < 0)
543 		    best = i;
544 	    }
545 	}
546     }
547 #endif
548     if (best > -1) {
549 	context->visual = vinfo[best].visual;
550 	context->depth = vinfo[best].depth;
551 	context->vclass = vinfo[best].class;
552 	getColormap(context, screen_number);
553 	attr.colormap = context->cmap;
554 	attr.override_redirect = True;
555 	attr.border_pixel = 0;
556 	context->drawable =
557 	    XCreateWindow(dpy, RootWindow(dpy, screen_number),
558 			  1, 1, 1, 1, 0, context->depth,
559 			  CopyFromParent, context->visual,
560 			  CWBorderPixel | CWColormap | CWOverrideRedirect,
561 			  &attr);
562 /*      XSetWindowColormap(dpy, context->drawable, context->cmap); */
563     }
564     if (vinfo)
565 	XFree((char *) vinfo);
566 
567     if (best < 0)
568 	return False;
569     else
570 	return True;
571 }
572