1 /* context.c - X context management
3 * Raster graphics library
5 * Copyright (c) 1997, 1998, 1999 Alfredo K. Kojima
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <X11/Xutil.h>
26 #include <X11/Xatom.h>
38 extern void _wraster_change_filter(int type
);
41 static Bool
bestContext(Display
*dpy
, int screen_number
, RContext
*context
);
43 static RContextAttributes DEFAULT_CONTEXT_ATTRIBS
= {
44 RC_UseSharedMemory
|RC_RenderMode
|RC_ColorsPerChannel
, /* flags */
45 RDitheredRendering
, /* render_mode */
46 4, /* colors_per_channel */
51 True
, /* use_shared_memory */
57 allocatePseudoColor(RContext
*ctx
)
62 int i
, ncolors
, r
, g
, b
;
64 int cpc
= ctx
->attribs
->colors_per_channel
;
66 ncolors
= cpc
* cpc
* cpc
;
68 if ( ncolors
> (1<<ctx
->depth
) ) {
69 /* reduce colormap size */
70 cpc
= ctx
->attribs
->colors_per_channel
= 1<<((int)ctx
->depth
/3);
71 ncolors
= cpc
* cpc
* cpc
;
74 assert(cpc
>= 2 && ncolors
<= (1<<ctx
->depth
));
76 colors
= malloc(sizeof(XColor
)*ncolors
);
78 RErrorCode
= RERR_NOMEMORY
;
83 if ((ctx
->attribs
->flags
& RC_GammaCorrection
) && ctx
->attribs
->rgamma
> 0
84 && ctx
->attribs
->ggamma
> 0 && ctx
->attribs
->bgamma
> 0) {
88 /* do gamma correction */
89 rg
= 1.0/ctx
->attribs
->rgamma
;
90 gg
= 1.0/ctx
->attribs
->ggamma
;
91 bg
= 1.0/ctx
->attribs
->bgamma
;
92 for (r
=0; r
<cpc
; r
++) {
93 for (g
=0; g
<cpc
; g
++) {
94 for (b
=0; b
<cpc
; b
++) {
95 colors
[i
].red
=(r
*0xffff) / (cpc
-1);
96 colors
[i
].green
=(g
*0xffff) / (cpc
-1);
97 colors
[i
].blue
=(b
*0xffff) / (cpc
-1);
98 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
100 tmp
= (double)colors
[i
].red
/ 65536.0;
101 colors
[i
].red
= (unsigned short)(65536.0*pow(tmp
, rg
));
103 tmp
= (double)colors
[i
].green
/ 65536.0;
104 colors
[i
].green
= (unsigned short)(65536.0*pow(tmp
, gg
));
106 tmp
= (double)colors
[i
].blue
/ 65536.0;
107 colors
[i
].blue
= (unsigned short)(65536.0*pow(tmp
, bg
));
115 for (r
=0; r
<cpc
; r
++) {
116 for (g
=0; g
<cpc
; g
++) {
117 for (b
=0; b
<cpc
; b
++) {
118 colors
[i
].red
=(r
*0xffff) / (cpc
-1);
119 colors
[i
].green
=(g
*0xffff) / (cpc
-1);
120 colors
[i
].blue
=(b
*0xffff) / (cpc
-1);
121 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
127 /* try to allocate the colors */
128 for (i
=0; i
<ncolors
; i
++) {
129 if (!XAllocColor(ctx
->dpy
, ctx
->cmap
, &(colors
[i
]))) {
130 colors
[i
].flags
= 0; /* failed */
132 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
135 /* try to allocate close values for the colors that couldn't
136 * be allocated before */
137 avncolors
= (1<<ctx
->depth
>256 ? 256 : 1<<ctx
->depth
);
138 for (i
=0; i
<avncolors
; i
++) avcolors
[i
].pixel
= i
;
140 XQueryColors(ctx
->dpy
, ctx
->cmap
, avcolors
, avncolors
);
142 for (i
=0; i
<ncolors
; i
++) {
143 if (colors
[i
].flags
==0) {
145 unsigned long cdiff
=0xffffffff, diff
;
146 unsigned long closest
=0;
151 /* find closest color */
152 for (j
=0; j
<avncolors
; j
++) {
153 r
= (colors
[i
].red
- avcolors
[i
].red
)>>8;
154 g
= (colors
[i
].green
- avcolors
[i
].green
)>>8;
155 b
= (colors
[i
].blue
- avcolors
[i
].blue
)>>8;
156 diff
= r
*r
+ g
*g
+ b
*b
;
162 /* allocate closest color found */
163 colors
[i
].red
= avcolors
[closest
].red
;
164 colors
[i
].green
= avcolors
[closest
].green
;
165 colors
[i
].blue
= avcolors
[closest
].blue
;
166 if (XAllocColor(ctx
->dpy
, ctx
->cmap
, &colors
[i
])) {
167 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
168 break; /* succeeded, don't need to retry */
171 printf("close color allocation failed. Retrying...\n");
181 allocateGrayScale(RContext
*ctx
)
184 XColor avcolors
[256];
186 int i
, ncolors
, r
, g
, b
;
188 int cpc
= ctx
->attribs
->colors_per_channel
;
190 ncolors
= cpc
* cpc
* cpc
;
192 if (ctx
->vclass
== StaticGray
) {
193 /* we might as well use all grays */
194 ncolors
= 1<<ctx
->depth
;
196 if ( ncolors
> (1<<ctx
->depth
) ) {
197 /* reduce colormap size */
198 cpc
= ctx
->attribs
->colors_per_channel
= 1<<((int)ctx
->depth
/3);
199 ncolors
= cpc
* cpc
* cpc
;
202 assert(cpc
>= 2 && ncolors
<= (1<<ctx
->depth
));
205 if (ncolors
>=256 && ctx
->vclass
==StaticGray
) {
206 /* don't need dithering for 256 levels of gray in StaticGray visual */
207 ctx
->attribs
->render_mode
= RBestMatchRendering
;
210 colors
= malloc(sizeof(XColor
)*ncolors
);
212 RErrorCode
= RERR_NOMEMORY
;
215 for (i
=0; i
<ncolors
; i
++) {
216 colors
[i
].red
=(i
*0xffff) / (ncolors
-1);
217 colors
[i
].green
=(i
*0xffff) / (ncolors
-1);
218 colors
[i
].blue
=(i
*0xffff) / (ncolors
-1);
219 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
221 /* try to allocate the colors */
222 for (i
=0; i
<ncolors
; i
++) {
224 printf("trying:%x,%x,%x\n",colors
[i
].red
,colors
[i
].green
,colors
[i
].blue
);
226 if (!XAllocColor(ctx
->dpy
, ctx
->cmap
, &(colors
[i
]))) {
227 colors
[i
].flags
= 0; /* failed */
229 printf("failed:%x,%x,%x\n",colors
[i
].red
,colors
[i
].green
,colors
[i
].blue
);
232 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
234 printf("success:%x,%x,%x\n",colors
[i
].red
,colors
[i
].green
,colors
[i
].blue
);
238 /* try to allocate close values for the colors that couldn't
239 * be allocated before */
240 avncolors
= (1<<ctx
->depth
>256 ? 256 : 1<<ctx
->depth
);
241 for (i
=0; i
<avncolors
; i
++) avcolors
[i
].pixel
= i
;
243 XQueryColors(ctx
->dpy
, ctx
->cmap
, avcolors
, avncolors
);
245 for (i
=0; i
<ncolors
; i
++) {
246 if (colors
[i
].flags
==0) {
248 unsigned long cdiff
=0xffffffff, diff
;
249 unsigned long closest
=0;
254 /* find closest color */
255 for (j
=0; j
<avncolors
; j
++) {
256 r
= (colors
[i
].red
- avcolors
[i
].red
)>>8;
257 g
= (colors
[i
].green
- avcolors
[i
].green
)>>8;
258 b
= (colors
[i
].blue
- avcolors
[i
].blue
)>>8;
259 diff
= r
*r
+ g
*g
+ b
*b
;
265 /* allocate closest color found */
267 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
);
269 colors
[i
].red
= avcolors
[closest
].red
;
270 colors
[i
].green
= avcolors
[closest
].green
;
271 colors
[i
].blue
= avcolors
[closest
].blue
;
272 if (XAllocColor(ctx
->dpy
, ctx
->cmap
, &colors
[i
])) {
273 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
274 break; /* succeeded, don't need to retry */
277 printf("close color allocation failed. Retrying...\n");
287 mygetenv(char *var
, int scr
)
292 sprintf(varname
, "%s%i", var
, scr
);
302 gatherconfig(RContext
*context
, int screen_n
)
306 ptr
= mygetenv("WRASTER_GAMMA", screen_n
);
309 if (sscanf(ptr
, "%f/%f/%f", &g1
, &g2
, &g3
)!=3
310 || g1
<=0.0 || g2
<=0.0 || g3
<=0.0) {
311 printf("wrlib: invalid value(s) for gamma correction \"%s\"\n",
314 context
->attribs
->flags
|= RC_GammaCorrection
;
315 context
->attribs
->rgamma
= g1
;
316 context
->attribs
->ggamma
= g2
;
317 context
->attribs
->bgamma
= g3
;
320 ptr
= mygetenv("WRASTER_COLOR_RESOLUTION", screen_n
);
323 if (sscanf(ptr
, "%d", &i
)!=1 || i
<2 || i
>6) {
324 printf("wrlib: invalid value for color resolution \"%s\"\n",ptr
);
326 context
->attribs
->flags
|= RC_ColorsPerChannel
;
327 context
->attribs
->colors_per_channel
= i
;
334 getColormap(RContext
*context
, int screen_number
)
336 Colormap cmap
= None
;
337 XStandardColormap
*cmaps
;
340 if (XGetRGBColormaps(context
->dpy
,
341 RootWindow(context
->dpy
, screen_number
),
342 &cmaps
, &ncmaps
, XA_RGB_DEFAULT_MAP
)) {
343 for (i
=0; i
<ncmaps
; ++i
) {
344 if (cmaps
[i
].visualid
== context
->visual
->visualid
) {
346 cmap
= cmaps
[i
].colormap
;
355 cmap
= XCreateColormap(context
->dpy
,
356 RootWindow(context
->dpy
, screen_number
),
357 context
->visual
, AllocNone
);
359 color
.red
= color
.green
= color
.blue
= 0;
360 XAllocColor(context
->dpy
, cmap
, &color
);
361 context
->black
= color
.pixel
;
363 color
.red
= color
.green
= color
.blue
= 0xffff;
364 XAllocColor(context
->dpy
, cmap
, &color
);
365 context
->white
= color
.pixel
;
368 context
->cmap
= cmap
;
373 count_offset(unsigned long mask
)
378 while ((mask
& 1)==0) {
387 RCreateContext(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 _wraster_change_filter(context
->attribs
->scaling_filter
);
420 if ((context
->attribs
->flags
& RC_VisualID
)) {
421 XVisualInfo
*vinfo
, templ
;
424 templ
.screen
= screen_number
;
425 templ
.visualid
= context
->attribs
->visualid
;
426 vinfo
= XGetVisualInfo(context
->dpy
, VisualIDMask
|VisualScreenMask
,
428 if (!vinfo
|| nret
==0) {
430 RErrorCode
= RERR_BADVISUALID
;
434 if (vinfo
[0].visual
== DefaultVisual(dpy
, screen_number
)) {
435 context
->attribs
->flags
|= RC_DefaultVisual
;
437 XSetWindowAttributes attr
;
440 context
->visual
= vinfo
[0].visual
;
441 context
->depth
= vinfo
[0].depth
;
442 context
->vclass
= vinfo
[0].class;
443 getColormap(context
, screen_number
);
444 attr
.colormap
= context
->cmap
;
445 attr
.override_redirect
= True
;
446 attr
.border_pixel
= 0;
447 attr
.background_pixel
= 0;
448 mask
= CWBorderPixel
|CWColormap
|CWOverrideRedirect
|CWBackPixel
;
450 XCreateWindow(dpy
, RootWindow(dpy
, screen_number
), 1, 1,
451 1, 1, 0, context
->depth
, CopyFromParent
,
452 context
->visual
, mask
, &attr
);
453 /* XSetWindowColormap(dpy, context->drawable, attr.colormap);*/
459 if (!context
->visual
) {
460 if ((context
->attribs
->flags
& RC_DefaultVisual
)
461 || !bestContext(dpy
, screen_number
, context
)) {
462 context
->visual
= DefaultVisual(dpy
, screen_number
);
463 context
->depth
= DefaultDepth(dpy
, screen_number
);
464 context
->cmap
= DefaultColormap(dpy
, screen_number
);
465 context
->drawable
= RootWindow(dpy
, screen_number
);
466 context
->black
= BlackPixel(dpy
, screen_number
);
467 context
->white
= WhitePixel(dpy
, screen_number
);
468 context
->vclass
= context
->visual
->class;
472 gcv
.function
= GXcopy
;
473 gcv
.graphics_exposures
= False
;
474 context
->copy_gc
= XCreateGC(dpy
, context
->drawable
, GCFunction
475 |GCGraphicsExposures
, &gcv
);
477 if (context
->vclass
== PseudoColor
|| context
->vclass
== StaticColor
) {
478 context
->colors
= allocatePseudoColor(context
);
479 if (!context
->colors
) {
482 } else if (context
->vclass
== GrayScale
|| context
->vclass
== StaticGray
) {
483 context
->colors
= allocateGrayScale(context
);
484 if (!context
->colors
) {
487 } else if (context
->vclass
== TrueColor
) {
488 /* calc offsets to create a TrueColor pixel */
489 context
->red_offset
= count_offset(context
->visual
->red_mask
);
490 context
->green_offset
= count_offset(context
->visual
->green_mask
);
491 context
->blue_offset
= count_offset(context
->visual
->blue_mask
);
492 /* disable dithering on 24 bits visuals */
493 if (context
->depth
>= 24)
494 context
->attribs
->render_mode
= RBestMatchRendering
;
497 /* check avaiability of MIT-SHM */
499 if (!(context
->attribs
->flags
& RC_UseSharedMemory
)) {
500 context
->attribs
->flags
|= RC_UseSharedMemory
;
501 context
->attribs
->use_shared_memory
= True
;
504 if (context
->attribs
->use_shared_memory
) {
508 context
->flags
.use_shared_pixmap
= 0;
510 if (!XShmQueryVersion(context
->dpy
, &major
, &minor
, &sharedPixmaps
)) {
511 context
->attribs
->use_shared_memory
= False
;
513 if (XShmPixmapFormat(context
->dpy
)==ZPixmap
)
514 context
->flags
.use_shared_pixmap
= sharedPixmaps
;
524 bestContext(Display
*dpy
, int screen_number
, RContext
*context
)
526 XVisualInfo
*vinfo
=NULL
, rvinfo
;
527 int best
= -1, numvis
, i
;
529 XSetWindowAttributes attr
;
531 rvinfo
.class = TrueColor
;
532 rvinfo
.screen
= screen_number
;
533 flags
= VisualClassMask
| VisualScreenMask
;
535 vinfo
= XGetVisualInfo(dpy
, flags
, &rvinfo
, &numvis
);
536 if (vinfo
) { /* look for a TrueColor, 24-bit or more (pref 24) */
537 for (i
=numvis
-1, best
= -1; i
>=0; i
--) {
538 if (vinfo
[i
].depth
== 24) best
= i
;
539 else if (vinfo
[i
].depth
>24 && best
<0) best
= i
;
544 if (best
== -1) { /* look for a DirectColor, 24-bit or more (pref 24) */
545 rvinfo
.class = DirectColor
;
546 if (vinfo
) XFree((char *) vinfo
);
547 vinfo
= XGetVisualInfo(dpy
, flags
, &rvinfo
, &numvis
);
549 for (i
=0, best
= -1; i
<numvis
; i
++) {
550 if (vinfo
[i
].depth
== 24) best
= i
;
551 else if (vinfo
[i
].depth
>24 && best
<0) best
= i
;
557 context
->visual
= vinfo
[best
].visual
;
558 context
->depth
= vinfo
[best
].depth
;
559 context
->vclass
= vinfo
[best
].class;
560 getColormap(context
, screen_number
);
561 attr
.colormap
= context
->cmap
;
562 attr
.override_redirect
= True
;
563 attr
.border_pixel
= 0;
565 XCreateWindow(dpy
, RootWindow(dpy
, screen_number
),
566 1, 1, 1, 1, 0, context
->depth
,
567 CopyFromParent
, context
->visual
,
568 CWBorderPixel
|CWColormap
|CWOverrideRedirect
, &attr
);
569 /* XSetWindowColormap(dpy, context->drawable, context->cmap);*/
571 if (vinfo
) XFree((char *) vinfo
);