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