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 :
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.
31 * #include <X11/Xlib.h>
32 * #include <X11/Xutil.h>
33 * #include <X11/Xatom.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 */
51 0, /* colors_per_channel */
56 0 /* NO use_shared_memory */
61 allocatePseudoColor(RContext
* ctx
)
66 int i
, ncolors
, r
, g
, b
;
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
);
81 RErrorCode
= RERR_NOMEMORY
;
86 if ((ctx
->attribs
->flags
& RC_GammaCorrection
) && ctx
->attribs
->rgamma
> 0
87 && ctx
->attribs
->ggamma
> 0 && ctx
->attribs
->bgamma
> 0) {
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
));
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
;
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 */
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) {
149 unsigned long cdiff
= 0xffffffff, diff
;
150 unsigned long closest
= 0;
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
;
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 */
175 printf("close color allocation failed. Retrying...\n");
185 allocateGrayScale(RContext
* ctx
)
188 XColor avcolors
[256];
190 int i
, ncolors
, r
, g
, b
;
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
;
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
);
214 RErrorCode
= RERR_NOMEMORY
;
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
++) {
226 printf("trying:%x,%x,%x\n", colors
[i
].red
, colors
[i
].green
, colors
[i
].blue
);
228 if (!XAllocColor(ctx
->dpy
, ctx
->cmap
, &(colors
[i
]))) {
229 colors
[i
].flags
= 0; /* failed */
231 printf("failed:%x,%x,%x\n", colors
[i
].red
, colors
[i
].green
, colors
[i
].blue
);
234 colors
[i
].flags
= DoRed
| DoGreen
| DoBlue
;
236 printf("success:%x,%x,%x\n", colors
[i
].red
, colors
[i
].green
, colors
[i
].blue
);
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) {
251 unsigned long cdiff
= 0xffffffff, diff
;
252 unsigned long closest
= 0;
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
;
268 /* allocate closest color found */
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
);
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 */
280 printf("close color allocation failed. Retrying...\n");
290 mygetenv(char *var
, int scr
)
295 sprintf(varname
, "%s%i", var
, scr
);
304 static void gatherconfig(RContext
* context
, int screen_n
)
308 ptr
= mygetenv("WRASTER_GAMMA", screen_n
);
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",
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
);
325 if (sscanf(ptr
, "%d", &i
) != 1 || i
< 2 || i
> 6) {
326 printf("wrlib: invalid value for color resolution \"%s\"\n", ptr
);
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
;
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
) {
347 cmap
= cmaps
[i
].colormap
;
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
)
378 while ((mask
& 1) == 0) {
387 myRCreateContext(Display
* dpy
, int screen_number
, RContextAttributes
* attribs
)
393 context
= malloc(sizeof(RContext
));
395 RErrorCode
= RERR_NOMEMORY
;
398 memset(context
, 0, sizeof(RContext
));
402 context
->screen_number
= screen_number
;
404 context
->attribs
= malloc(sizeof(RContextAttributes
));
405 if (!context
->attribs
) {
407 RErrorCode
= RERR_NOMEMORY
;
411 *context
->attribs
= DEFAULT_CONTEXT_ATTRIBS
;
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
;
422 templ
.screen
= screen_number
;
423 templ
.visualid
= context
->attribs
->visualid
;
424 vinfo
= XGetVisualInfo(context
->dpy
, VisualIDMask
| VisualScreenMask
,
426 if (!vinfo
|| nret
== 0) {
428 RErrorCode
= RERR_BADVISUALID
;
431 if (vinfo
[0].visual
== DefaultVisual(dpy
, screen_number
)) {
432 context
->attribs
->flags
|= RC_DefaultVisual
;
434 XSetWindowAttributes attr
;
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
;
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); */
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
) {
477 } else if (context
->vclass
== GrayScale
|| context
->vclass
== StaticGray
) {
478 context
->colors
= allocateGrayScale(context
);
479 if (!context
->colors
) {
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 */
498 bestContext(Display
* dpy
, int screen_number
, RContext
* context
)
500 XVisualInfo
*vinfo
= NULL
, rvinfo
;
501 int best
= -1, numvis
, i
;
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)
514 else if (vinfo
[i
].depth
> 24 && best
< 0)
519 if (best
== -1) { /* look for a DirectColor, 24-bit or more (pref 24) */
520 rvinfo
.class = DirectColor
;
522 XFree((char *) vinfo
);
523 vinfo
= XGetVisualInfo(dpy
, flags
, &rvinfo
, &numvis
);
525 for (i
= 0, best
= -1; i
< numvis
; i
++) {
526 if (vinfo
[i
].depth
== 24)
528 else if (vinfo
[i
].depth
> 24 && best
< 0)
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;
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); */
550 XFree((char *) vinfo
);