wmmoonclock: Bump to version 1.29.
[dockapps.git] / wmglobe / src / mycontext.c
blob8479d343c65fb4d4744e4c5a094d2a2f20ad479c
1 /* WMGlobe 0.5 - 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
8 * Copyright (c) 1997 Alfredo K. Kojima
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.
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.
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.
26 * #include <config.h>
28 #include "wmglobe.h"
31 * #include <X11/Xlib.h>
32 * #include <X11/Xutil.h>
33 * #include <X11/Xatom.h>
35 * #include <stdio.h>
36 * #include <stdlib.h>
37 * #include <string.h>
38 * #include <assert.h>
40 * #include <math.h>
42 * #include "wraster.h"
45 static Bool bestContext(Display * dpy, int screen_number, RContext * context);
47 static RContextAttributes DEFAULT_CONTEXT_ATTRIBS =
49 RC_DefaultVisual, /* flags */
50 0, /* render_mode */
51 0, /* colors_per_channel */
56 0 /* NO use_shared_memory */
60 static XColor *
61 allocatePseudoColor(RContext * ctx)
63 XColor *colors;
64 XColor avcolors[256];
65 int avncolors;
66 int i, ncolors, r, g, b;
67 int retries;
68 int cpc = ctx->attribs->colors_per_channel;
70 ncolors = cpc * cpc * cpc;
72 if (ncolors > (1 << ctx->depth)) {
73 /* reduce colormap size */
74 cpc = ctx->attribs->colors_per_channel = 1 << ((int) ctx->depth / 3);
75 ncolors = cpc * cpc * cpc;
77 assert(cpc >= 2 && ncolors <= (1 << ctx->depth));
79 colors = malloc(sizeof(XColor) * ncolors);
80 if (!colors) {
81 RErrorCode = RERR_NOMEMORY;
82 return NULL;
84 i = 0;
86 if ((ctx->attribs->flags & RC_GammaCorrection) && ctx->attribs->rgamma > 0
87 && ctx->attribs->ggamma > 0 && ctx->attribs->bgamma > 0) {
88 double rg, gg, bg;
89 double tmp;
91 /* do gamma correction */
92 rg = 1.0 / ctx->attribs->rgamma;
93 gg = 1.0 / ctx->attribs->ggamma;
94 bg = 1.0 / ctx->attribs->bgamma;
95 for (r = 0; r < cpc; r++) {
96 for (g = 0; g < cpc; g++) {
97 for (b = 0; b < cpc; b++) {
98 colors[i].red = (r * 0xffff) / (cpc - 1);
99 colors[i].green = (g * 0xffff) / (cpc - 1);
100 colors[i].blue = (b * 0xffff) / (cpc - 1);
101 colors[i].flags = DoRed | DoGreen | DoBlue;
103 tmp = (double) colors[i].red / 65536.0;
104 colors[i].red = (unsigned short) (65536.0 * pow(tmp, rg));
106 tmp = (double) colors[i].green / 65536.0;
107 colors[i].green = (unsigned short) (65536.0 * pow(tmp, gg));
109 tmp = (double) colors[i].blue / 65536.0;
110 colors[i].blue = (unsigned short) (65536.0 * pow(tmp, bg));
112 i++;
117 } else {
118 for (r = 0; r < cpc; r++) {
119 for (g = 0; g < cpc; g++) {
120 for (b = 0; b < cpc; b++) {
121 colors[i].red = (r * 0xffff) / (cpc - 1);
122 colors[i].green = (g * 0xffff) / (cpc - 1);
123 colors[i].blue = (b * 0xffff) / (cpc - 1);
124 colors[i].flags = DoRed | DoGreen | DoBlue;
125 i++;
130 /* try to allocate the colors */
131 for (i = 0; i < ncolors; i++) {
132 if (!XAllocColor(ctx->dpy, ctx->cmap, &(colors[i]))) {
133 colors[i].flags = 0; /* failed */
134 } else {
135 colors[i].flags = DoRed | DoGreen | DoBlue;
138 /* try to allocate close values for the colors that couldn't
139 * be allocated before */
140 avncolors = (1 << ctx->depth > 256 ? 256 : 1 << ctx->depth);
141 for (i = 0; i < avncolors; i++)
142 avcolors[i].pixel = i;
144 XQueryColors(ctx->dpy, ctx->cmap, avcolors, avncolors);
146 for (i = 0; i < ncolors; i++) {
147 if (colors[i].flags == 0) {
148 int j;
149 unsigned long cdiff = 0xffffffff, diff;
150 unsigned long closest = 0;
152 retries = 2;
154 while (retries--) {
155 /* find closest color */
156 for (j = 0; j < avncolors; j++) {
157 r = (colors[i].red - avcolors[i].red) >> 8;
158 g = (colors[i].green - avcolors[i].green) >> 8;
159 b = (colors[i].blue - avcolors[i].blue) >> 8;
160 diff = r * r + g * g + b * b;
161 if (diff < cdiff) {
162 cdiff = diff;
163 closest = j;
166 /* allocate closest color found */
167 colors[i].red = avcolors[closest].red;
168 colors[i].green = avcolors[closest].green;
169 colors[i].blue = avcolors[closest].blue;
170 if (XAllocColor(ctx->dpy, ctx->cmap, &colors[i])) {
171 colors[i].flags = DoRed | DoGreen | DoBlue;
172 break; /* succeeded, don't need to retry */
174 #ifdef DEBUG
175 printf("close color allocation failed. Retrying...\n");
176 #endif
180 return colors;
184 static XColor *
185 allocateGrayScale(RContext * ctx)
187 XColor *colors;
188 XColor avcolors[256];
189 int avncolors;
190 int i, ncolors, r, g, b;
191 int retries;
192 int cpc = ctx->attribs->colors_per_channel;
194 ncolors = cpc * cpc * cpc;
196 if (ctx->vclass == StaticGray) {
197 /* we might as well use all grays */
198 ncolors = 1 << ctx->depth;
199 } else {
200 if (ncolors > (1 << ctx->depth)) {
201 /* reduce colormap size */
202 cpc = ctx->attribs->colors_per_channel = 1 << ((int) ctx->depth / 3);
203 ncolors = cpc * cpc * cpc;
205 assert(cpc >= 2 && ncolors <= (1 << ctx->depth));
208 if (ncolors >= 256 && ctx->vclass == StaticGray) {
209 /* don't need dithering for 256 levels of gray in StaticGray visual */
210 ctx->attribs->render_mode = RM_MATCH;
212 colors = malloc(sizeof(XColor) * ncolors);
213 if (!colors) {
214 RErrorCode = RERR_NOMEMORY;
215 return False;
217 for (i = 0; i < ncolors; i++) {
218 colors[i].red = (i * 0xffff) / (ncolors - 1);
219 colors[i].green = (i * 0xffff) / (ncolors - 1);
220 colors[i].blue = (i * 0xffff) / (ncolors - 1);
221 colors[i].flags = DoRed | DoGreen | DoBlue;
223 /* try to allocate the colors */
224 for (i = 0; i < ncolors; i++) {
225 #ifdef DEBUG
226 printf("trying:%x,%x,%x\n", colors[i].red, colors[i].green, colors[i].blue);
227 #endif
228 if (!XAllocColor(ctx->dpy, ctx->cmap, &(colors[i]))) {
229 colors[i].flags = 0; /* failed */
230 #ifdef DEBUG
231 printf("failed:%x,%x,%x\n", colors[i].red, colors[i].green, colors[i].blue);
232 #endif
233 } else {
234 colors[i].flags = DoRed | DoGreen | DoBlue;
235 #ifdef DEBUG
236 printf("success:%x,%x,%x\n", colors[i].red, colors[i].green, colors[i].blue);
237 #endif
240 /* try to allocate close values for the colors that couldn't
241 * be allocated before */
242 avncolors = (1 << ctx->depth > 256 ? 256 : 1 << ctx->depth);
243 for (i = 0; i < avncolors; i++)
244 avcolors[i].pixel = i;
246 XQueryColors(ctx->dpy, ctx->cmap, avcolors, avncolors);
248 for (i = 0; i < ncolors; i++) {
249 if (colors[i].flags == 0) {
250 int j;
251 unsigned long cdiff = 0xffffffff, diff;
252 unsigned long closest = 0;
254 retries = 2;
256 while (retries--) {
257 /* find closest color */
258 for (j = 0; j < avncolors; j++) {
259 r = (colors[i].red - avcolors[i].red) >> 8;
260 g = (colors[i].green - avcolors[i].green) >> 8;
261 b = (colors[i].blue - avcolors[i].blue) >> 8;
262 diff = r * r + g * g + b * b;
263 if (diff < cdiff) {
264 cdiff = diff;
265 closest = j;
268 /* allocate closest color found */
269 #ifdef DEBUG
270 printf("best match:%x,%x,%x => %x,%x,%x\n", colors[i].red, colors[i].green, colors[i].blue, avcolors[closest].red, avcolors[closest].green, avcolors[closest].blue);
271 #endif
272 colors[i].red = avcolors[closest].red;
273 colors[i].green = avcolors[closest].green;
274 colors[i].blue = avcolors[closest].blue;
275 if (XAllocColor(ctx->dpy, ctx->cmap, &colors[i])) {
276 colors[i].flags = DoRed | DoGreen | DoBlue;
277 break; /* succeeded, don't need to retry */
279 #ifdef DEBUG
280 printf("close color allocation failed. Retrying...\n");
281 #endif
285 return colors;
289 static char *
290 mygetenv(char *var, int scr)
292 char *p;
293 char varname[64];
295 sprintf(varname, "%s%i", var, scr);
296 p = getenv(varname);
297 if (!p) {
298 p = getenv(var);
300 return p;
304 static void gatherconfig(RContext * context, int screen_n)
306 char *ptr;
308 ptr = mygetenv("WRASTER_GAMMA", screen_n);
309 if (ptr) {
310 float g1, g2, g3;
311 if (sscanf(ptr, "%f/%f/%f", &g1, &g2, &g3) != 3
312 || g1 <= 0.0 || g2 <= 0.0 || g3 <= 0.0) {
313 printf("wrlib: invalid value(s) for gamma correction \"%s\"\n",
314 ptr);
315 } else {
316 context->attribs->flags |= RC_GammaCorrection;
317 context->attribs->rgamma = g1;
318 context->attribs->ggamma = g2;
319 context->attribs->bgamma = g3;
322 ptr = mygetenv("WRASTER_COLOR_RESOLUTION", screen_n);
323 if (ptr) {
324 int i;
325 if (sscanf(ptr, "%d", &i) != 1 || i < 2 || i > 6) {
326 printf("wrlib: invalid value for color resolution \"%s\"\n", ptr);
327 } else {
328 context->attribs->flags |= RC_ColorsPerChannel;
329 context->attribs->colors_per_channel = i;
335 static void getColormap(RContext * context, int screen_number)
337 Colormap cmap = None;
338 XStandardColormap *cmaps;
339 int ncmaps, i;
341 if (XGetRGBColormaps(context->dpy,
342 RootWindow(context->dpy, screen_number),
343 &cmaps, &ncmaps, XA_RGB_DEFAULT_MAP)) {
344 for (i = 0; i < ncmaps; ++i) {
345 if (cmaps[i].visualid == context->visual->visualid) {
346 puts("ACHOU");
347 cmap = cmaps[i].colormap;
348 break;
351 XFree(cmaps);
353 if (cmap == None) {
354 XColor color;
356 cmap = XCreateColormap(context->dpy,
357 RootWindow(context->dpy, screen_number),
358 context->visual, AllocNone);
360 color.red = color.green = color.blue = 0;
361 XAllocColor(context->dpy, cmap, &color);
362 context->black = color.pixel;
364 color.red = color.green = color.blue = 0xffff;
365 XAllocColor(context->dpy, cmap, &color);
366 context->white = color.pixel;
369 context->cmap = cmap;
373 static int count_offset(unsigned long mask)
375 int i;
377 i = 0;
378 while ((mask & 1) == 0) {
379 i++;
380 mask = mask >> 1;
382 return i;
386 RContext *
387 myRCreateContext(Display * dpy, int screen_number, RContextAttributes * attribs)
389 RContext *context;
390 XGCValues gcv;
393 context = malloc(sizeof(RContext));
394 if (!context) {
395 RErrorCode = RERR_NOMEMORY;
396 return NULL;
398 memset(context, 0, sizeof(RContext));
400 context->dpy = dpy;
402 context->screen_number = screen_number;
404 context->attribs = malloc(sizeof(RContextAttributes));
405 if (!context->attribs) {
406 free(context);
407 RErrorCode = RERR_NOMEMORY;
408 return NULL;
410 if (!attribs)
411 *context->attribs = DEFAULT_CONTEXT_ATTRIBS;
412 else
413 *context->attribs = *attribs;
415 /* get configuration from environment variables */
416 gatherconfig(context, screen_number);
418 if ((context->attribs->flags & RC_VisualID)) {
419 XVisualInfo *vinfo, templ;
420 int nret;
422 templ.screen = screen_number;
423 templ.visualid = context->attribs->visualid;
424 vinfo = XGetVisualInfo(context->dpy, VisualIDMask | VisualScreenMask,
425 &templ, &nret);
426 if (!vinfo || nret == 0) {
427 free(context);
428 RErrorCode = RERR_BADVISUALID;
429 return NULL;
431 if (vinfo[0].visual == DefaultVisual(dpy, screen_number)) {
432 context->attribs->flags |= RC_DefaultVisual;
433 } else {
434 XSetWindowAttributes attr;
435 unsigned long mask;
437 context->visual = vinfo[0].visual;
438 context->depth = vinfo[0].depth;
439 context->vclass = vinfo[0].class;
440 getColormap(context, screen_number);
441 attr.colormap = context->cmap;
442 attr.override_redirect = True;
443 attr.border_pixel = 0;
444 attr.background_pixel = 0;
445 mask = CWBorderPixel | CWColormap | CWOverrideRedirect | CWBackPixel;
446 context->drawable =
447 XCreateWindow(dpy, RootWindow(dpy, screen_number), 1, 1,
448 1, 1, 0, context->depth, CopyFromParent,
449 context->visual, mask, &attr);
450 /* XSetWindowColormap(dpy, context->drawable, attr.colormap); */
452 XFree(vinfo);
454 /* use default */
455 if (!context->visual) {
456 if ((context->attribs->flags & RC_DefaultVisual)
457 || !bestContext(dpy, screen_number, context)) {
458 context->visual = DefaultVisual(dpy, screen_number);
459 context->depth = DefaultDepth(dpy, screen_number);
460 context->cmap = DefaultColormap(dpy, screen_number);
461 context->drawable = RootWindow(dpy, screen_number);
462 context->black = BlackPixel(dpy, screen_number);
463 context->white = WhitePixel(dpy, screen_number);
464 context->vclass = context->visual->class;
467 gcv.function = GXcopy;
468 gcv.graphics_exposures = False;
469 context->copy_gc = XCreateGC(dpy, context->drawable, GCFunction
470 | GCGraphicsExposures, &gcv);
472 if (context->vclass == PseudoColor || context->vclass == StaticColor) {
473 context->colors = allocatePseudoColor(context);
474 if (!context->colors) {
475 return NULL;
477 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
478 context->colors = allocateGrayScale(context);
479 if (!context->colors) {
480 return NULL;
482 } else if (context->vclass == TrueColor) {
483 /* calc offsets to create a TrueColor pixel */
484 context->red_offset = count_offset(context->visual->red_mask);
485 context->green_offset = count_offset(context->visual->green_mask);
486 context->blue_offset = count_offset(context->visual->blue_mask);
487 /* disable dithering on 24 bits visuals */
488 if (context->depth >= 24)
489 context->attribs->render_mode = RM_MATCH;
491 /* check avaiability of MIT-SHM */
493 return context;
497 static Bool
498 bestContext(Display * dpy, int screen_number, RContext * context)
500 XVisualInfo *vinfo = NULL, rvinfo;
501 int best = -1, numvis, i;
502 long flags;
503 XSetWindowAttributes attr;
505 rvinfo.class = TrueColor;
506 rvinfo.screen = screen_number;
507 flags = VisualClassMask | VisualScreenMask;
509 vinfo = XGetVisualInfo(dpy, flags, &rvinfo, &numvis);
510 if (vinfo) { /* look for a TrueColor, 24-bit or more (pref 24) */
511 for (i = numvis - 1, best = -1; i >= 0; i--) {
512 if (vinfo[i].depth == 24)
513 best = i;
514 else if (vinfo[i].depth > 24 && best < 0)
515 best = i;
518 #if 0
519 if (best == -1) { /* look for a DirectColor, 24-bit or more (pref 24) */
520 rvinfo.class = DirectColor;
521 if (vinfo)
522 XFree((char *) vinfo);
523 vinfo = XGetVisualInfo(dpy, flags, &rvinfo, &numvis);
524 if (vinfo) {
525 for (i = 0, best = -1; i < numvis; i++) {
526 if (vinfo[i].depth == 24)
527 best = i;
528 else if (vinfo[i].depth > 24 && best < 0)
529 best = i;
533 #endif
534 if (best > -1) {
535 context->visual = vinfo[best].visual;
536 context->depth = vinfo[best].depth;
537 context->vclass = vinfo[best].class;
538 getColormap(context, screen_number);
539 attr.colormap = context->cmap;
540 attr.override_redirect = True;
541 attr.border_pixel = 0;
542 context->drawable =
543 XCreateWindow(dpy, RootWindow(dpy, screen_number),
544 1, 1, 1, 1, 0, context->depth,
545 CopyFromParent, context->visual,
546 CWBorderPixel | CWColormap | CWOverrideRedirect, &attr);
547 /* XSetWindowColormap(dpy, context->drawable, context->cmap); */
549 if (vinfo)
550 XFree((char *) vinfo);
552 if (best < 0)
553 return False;
554 else
555 return True;