1
/* context.c - X context management
3
* Raster graphics library
5
* Copyright (c) 1997-2003 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>
40
extern void _wraster_change_filter(int type);
43
static Bool bestContext(Display *dpy, int screen_number, RContext *context);
45
static RContextAttributes DEFAULT_CONTEXT_ATTRIBS = {
46
RC_UseSharedMemory|RC_RenderMode|RC_ColorsPerChannel, /* flags */
47
RDitheredRendering, /* render_mode */
48
4, /* colors_per_channel */
53
True, /* use_shared_memory */
62
* Colormap allocation for PseudoColor visuals:
65
* switch standardColormap:
67
* allocate colors according to colors_per_channel
70
* if there's a std colormap defined then use it
73
* create a std colormap and set it
80
*----------------------------------------------------------------------
81
* allocateStandardPseudoColor
82
* Creates the internal colormap for PseudoColor, setting the
83
* color values according to the supplied standard colormap.
90
*----------------------------------------------------------------------
93
allocateStandardPseudoColor(RContext *ctx, XStandardColormap *stdcmap)
97
ctx->ncolors = stdcmap->red_max * stdcmap->red_mult
98
+ stdcmap->green_max * stdcmap->green_mult
99
+ stdcmap->blue_max * stdcmap->blue_mult + 1;
101
if (ctx->ncolors <= 1) {
102
RErrorCode = RERR_INTERNAL;
103
puts("wraster: bad standard colormap");
108
ctx->colors = malloc(sizeof(XColor)*ctx->ncolors);
110
RErrorCode = RERR_NOMEMORY;
115
ctx->pixels = malloc(sizeof(unsigned long)*ctx->ncolors);
121
RErrorCode = RERR_NOMEMORY;
127
#define calc(max,mult) (((i / stdcmap->mult) % \
128
(stdcmap->max + 1)) * 65535) / stdcmap->max
130
for (i = 0; i < ctx->ncolors; i++) {
131
ctx->colors[i].pixel = i + stdcmap->base_pixel;
132
ctx->colors[i].red = calc(red_max, red_mult);
133
ctx->colors[i].green = calc(green_max, green_mult);
134
ctx->colors[i].blue = calc(blue_max, blue_mult);
136
ctx->pixels[i] = ctx->colors[i].pixel;
146
setupStandardColormap(RContext *ctx, Atom property)
148
if (!XmuLookupStandardColormap(ctx->dpy, ctx->screen_number,
149
ctx->visual->visualid,
150
ctx->depth, property,
152
RErrorCode = RERR_STDCMAPFAIL;
168
allocatePseudoColor(RContext *ctx)
171
XColor avcolors[256];
173
int i, ncolors, r, g, b;
175
int cpc = ctx->attribs->colors_per_channel;
177
ncolors = cpc * cpc * cpc;
179
if (ncolors > (1<<ctx->depth)) {
180
/* reduce colormap size */
181
cpc = ctx->attribs->colors_per_channel = 1<<((int)ctx->depth/3);
182
ncolors = cpc * cpc * cpc;
185
assert(cpc >= 2 && ncolors <= (1<<ctx->depth));
187
colors = malloc(sizeof(XColor)*ncolors);
189
RErrorCode = RERR_NOMEMORY;
193
ctx->pixels = malloc(sizeof(unsigned long)*ncolors);
196
RErrorCode = RERR_NOMEMORY;
202
if ((ctx->attribs->flags & RC_GammaCorrection) && ctx->attribs->rgamma > 0
203
&& ctx->attribs->ggamma > 0 && ctx->attribs->bgamma > 0) {
207
/* do gamma correction */
208
rg = 1.0/ctx->attribs->rgamma;
209
gg = 1.0/ctx->attribs->ggamma;
210
bg = 1.0/ctx->attribs->bgamma;
211
for (r=0; r<cpc; r++) {
212
for (g=0; g<cpc; g++) {
213
for (b=0; b<cpc; b++) {
214
colors[i].red=(r*0xffff) / (cpc-1);
215
colors[i].green=(g*0xffff) / (cpc-1);
216
colors[i].blue=(b*0xffff) / (cpc-1);
217
colors[i].flags = DoRed|DoGreen|DoBlue;
219
tmp = (double)colors[i].red / 65536.0;
220
colors[i].red = (unsigned short)(65536.0*pow(tmp, rg));
222
tmp = (double)colors[i].green / 65536.0;
223
colors[i].green = (unsigned short)(65536.0*pow(tmp, gg));
225
tmp = (double)colors[i].blue / 65536.0;
226
colors[i].blue = (unsigned short)(65536.0*pow(tmp, bg));
234
for (r=0; r<cpc; r++) {
235
for (g=0; g<cpc; g++) {
236
for (b=0; b<cpc; b++) {
237
colors[i].red=(r*0xffff) / (cpc-1);
238
colors[i].green=(g*0xffff) / (cpc-1);
239
colors[i].blue=(b*0xffff) / (cpc-1);
240
colors[i].flags = DoRed|DoGreen|DoBlue;
246
/* try to allocate the colors */
247
for (i=0; i<ncolors; i++) {
248
if (!XAllocColor(ctx->dpy, ctx->cmap, &(colors[i]))) {
249
colors[i].flags = 0; /* failed */
251
colors[i].flags = DoRed|DoGreen|DoBlue;
254
/* try to allocate close values for the colors that couldn't
255
* be allocated before */
256
avncolors = (1<<ctx->depth>256 ? 256 : 1<<ctx->depth);
257
for (i=0; i<avncolors; i++) avcolors[i].pixel = i;
259
XQueryColors(ctx->dpy, ctx->cmap, avcolors, avncolors);
261
for (i=0; i<ncolors; i++) {
262
if (colors[i].flags==0) {
264
unsigned long cdiff=0xffffffff, diff;
265
unsigned long closest=0;
270
/* find closest color */
271
for (j=0; j<avncolors; j++) {
272
r = (colors[i].red - avcolors[i].red)>>8;
273
g = (colors[i].green - avcolors[i].green)>>8;
274
b = (colors[i].blue - avcolors[i].blue)>>8;
275
diff = r*r + g*g + b*b;
281
/* allocate closest color found */
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 */
290
printf("close color allocation failed. Retrying...\n");
296
ctx->colors = colors;
297
ctx->ncolors = ncolors;
299
/* fill the pixels shortcut array */
300
for (i = 0; i < ncolors; i++) {
301
ctx->pixels[i] = ctx->colors[i].pixel;
309
allocateGrayScale(RContext *ctx)
312
XColor avcolors[256];
314
int i, ncolors, r, g, b;
316
int cpc = ctx->attribs->colors_per_channel;
318
ncolors = cpc * cpc * cpc;
320
if (ctx->vclass == StaticGray) {
321
/* we might as well use all grays */
322
ncolors = 1<<ctx->depth;
324
if ( ncolors > (1<<ctx->depth) ) {
325
/* reduce colormap size */
326
cpc = ctx->attribs->colors_per_channel = 1<<((int)ctx->depth/3);
327
ncolors = cpc * cpc * cpc;
330
assert(cpc >= 2 && ncolors <= (1<<ctx->depth));
333
if (ncolors>=256 && ctx->vclass==StaticGray) {
334
/* don't need dithering for 256 levels of gray in StaticGray visual */
335
ctx->attribs->render_mode = RBestMatchRendering;
338
colors = malloc(sizeof(XColor)*ncolors);
340
RErrorCode = RERR_NOMEMORY;
343
for (i=0; i<ncolors; i++) {
344
colors[i].red=(i*0xffff) / (ncolors-1);
345
colors[i].green=(i*0xffff) / (ncolors-1);
346
colors[i].blue=(i*0xffff) / (ncolors-1);
347
colors[i].flags = DoRed|DoGreen|DoBlue;
349
/* try to allocate the colors */
350
for (i=0; i<ncolors; i++) {
352
printf("trying:%x,%x,%x\n",colors[i].red,colors[i].green,colors[i].blue);
354
if (!XAllocColor(ctx->dpy, ctx->cmap, &(colors[i]))) {
355
colors[i].flags = 0; /* failed */
357
printf("failed:%x,%x,%x\n",colors[i].red,colors[i].green,colors[i].blue);
360
colors[i].flags = DoRed|DoGreen|DoBlue;
362
printf("success:%x,%x,%x\n",colors[i].red,colors[i].green,colors[i].blue);
366
/* try to allocate close values for the colors that couldn't
367
* be allocated before */
368
avncolors = (1<<ctx->depth>256 ? 256 : 1<<ctx->depth);
369
for (i=0; i<avncolors; i++) avcolors[i].pixel = i;
371
XQueryColors(ctx->dpy, ctx->cmap, avcolors, avncolors);
373
for (i=0; i<ncolors; i++) {
374
if (colors[i].flags==0) {
376
unsigned long cdiff=0xffffffff, diff;
377
unsigned long closest=0;
382
/* find closest color */
383
for (j=0; j<avncolors; j++) {
384
r = (colors[i].red - avcolors[i].red)>>8;
385
g = (colors[i].green - avcolors[i].green)>>8;
386
b = (colors[i].blue - avcolors[i].blue)>>8;
387
diff = r*r + g*g + b*b;
393
/* allocate closest color found */
395
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);
397
colors[i].red = avcolors[closest].red;
398
colors[i].green = avcolors[closest].green;
399
colors[i].blue = avcolors[closest].blue;
400
if (XAllocColor(ctx->dpy, ctx->cmap, &colors[i])) {
401
colors[i].flags = DoRed|DoGreen|DoBlue;
402
break; /* succeeded, don't need to retry */
405
printf("close color allocation failed. Retrying...\n");
415
setupPseudoColorColormap(RContext *context)
419
if (context->attribs->standard_colormap_mode == RCreateStdColormap) {
420
property = XInternAtom(context->dpy, "RGB_DEFAULT_MAP", False);
422
if (!setupStandardColormap(context, property)) {
427
if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
428
XStandardColormap *maps;
432
property = XInternAtom(context->dpy, "RGB_BEST_MAP", False);
433
if (!XGetRGBColormaps(context->dpy,
434
DefaultRootWindow(context->dpy),
435
&maps, &count, property)) {
440
property = XInternAtom(context->dpy, "RGB_DEFAULT_MAP", False);
441
if (!XGetRGBColormaps(context->dpy,
442
DefaultRootWindow(context->dpy),
443
&maps, &count, property)) {
448
if (!XGetRGBColormaps(context->dpy,
449
DefaultRootWindow(context->dpy),
450
&maps, &count, property)) {
458
for (i = 0; i < count; i++) {
459
if (maps[i].visualid == context->visual->visualid) {
466
puts("wrlib: no std cmap found");
470
&& allocateStandardPseudoColor(context, &maps[theMap])) {
472
context->std_rgb_map = XAllocStandardColormap();
474
*context->std_rgb_map = maps[theMap];
476
context->cmap = context->std_rgb_map->colormap;
487
context->attribs->standard_colormap_mode = RIgnoreStdColormap;
489
/* RIgnoreStdColormap and fallback */
490
return allocatePseudoColor(context);
497
mygetenv(char *var, int scr)
502
sprintf(varname, "%s%i", var, scr);
512
gatherconfig(RContext *context, int screen_n)
516
ptr = mygetenv("WRASTER_GAMMA", screen_n);
519
if (sscanf(ptr, "%f/%f/%f", &g1, &g2, &g3)!=3
520
|| g1<=0.0 || g2<=0.0 || g3<=0.0) {
521
printf("wrlib: invalid value(s) for gamma correction \"%s\"\n",
524
context->attribs->flags |= RC_GammaCorrection;
525
context->attribs->rgamma = g1;
526
context->attribs->ggamma = g2;
527
context->attribs->bgamma = g3;
530
ptr = mygetenv("WRASTER_COLOR_RESOLUTION", screen_n);
533
if (sscanf(ptr, "%d", &i)!=1 || i<2 || i>6) {
534
printf("wrlib: invalid value for color resolution \"%s\"\n",ptr);
536
context->attribs->flags |= RC_ColorsPerChannel;
537
context->attribs->colors_per_channel = i;
541
ptr = mygetenv("WRASTER_OPTIMIZE_FOR_SPEED", screen_n);
543
context->flags.optimize_for_speed = 1;
545
context->flags.optimize_for_speed = 0;
552
getColormap(RContext *context, int screen_number)
554
Colormap cmap = None;
555
XStandardColormap *cmaps;
558
if (XGetRGBColormaps(context->dpy,
559
RootWindow(context->dpy, screen_number),
560
&cmaps, &ncmaps, XA_RGB_DEFAULT_MAP)) {
561
for (i=0; i<ncmaps; ++i) {
562
if (cmaps[i].visualid == context->visual->visualid) {
563
cmap = cmaps[i].colormap;
572
cmap = XCreateColormap(context->dpy,
573
RootWindow(context->dpy, screen_number),
574
context->visual, AllocNone);
576
color.red = color.green = color.blue = 0;
577
XAllocColor(context->dpy, cmap, &color);
578
context->black = color.pixel;
580
color.red = color.green = color.blue = 0xffff;
581
XAllocColor(context->dpy, cmap, &color);
582
context->white = color.pixel;
585
context->cmap = cmap;
590
count_offset(unsigned long mask)
595
while ((mask & 1)==0) {
604
RCreateContext(Display *dpy, int screen_number, RContextAttributes *attribs)
610
context = malloc(sizeof(RContext));
612
RErrorCode = RERR_NOMEMORY;
615
memset(context, 0, sizeof(RContext));
619
context->screen_number = screen_number;
621
context->attribs = malloc(sizeof(RContextAttributes));
622
if (!context->attribs) {
624
RErrorCode = RERR_NOMEMORY;
628
*context->attribs = DEFAULT_CONTEXT_ATTRIBS;
630
*context->attribs = *attribs;
632
if (!(context->attribs->flags & RC_StandardColormap)) {
633
context->attribs->standard_colormap_mode = RUseStdColormap;
636
if (!(context->attribs->flags & RC_ScalingFilter)) {
637
context->attribs->flags |= RC_ScalingFilter;
638
context->attribs->scaling_filter = RMitchellFilter;
641
/* get configuration from environment variables */
642
gatherconfig(context, screen_number);
644
_wraster_change_filter(context->attribs->scaling_filter);
646
if ((context->attribs->flags & RC_VisualID)) {
647
XVisualInfo *vinfo, templ;
650
templ.screen = screen_number;
651
templ.visualid = context->attribs->visualid;
652
vinfo = XGetVisualInfo(context->dpy, VisualIDMask|VisualScreenMask,
654
if (!vinfo || nret==0) {
656
RErrorCode = RERR_BADVISUALID;
660
if (vinfo[0].visual == DefaultVisual(dpy, screen_number)) {
661
context->attribs->flags |= RC_DefaultVisual;
663
XSetWindowAttributes attr;
666
context->visual = vinfo[0].visual;
667
context->depth = vinfo[0].depth;
668
context->vclass = vinfo[0].class;
669
getColormap(context, screen_number);
670
attr.colormap = context->cmap;
671
attr.override_redirect = True;
672
attr.border_pixel = 0;
673
attr.background_pixel = 0;
674
mask = CWBorderPixel|CWColormap|CWOverrideRedirect|CWBackPixel;
676
XCreateWindow(dpy, RootWindow(dpy, screen_number), 1, 1,
677
1, 1, 0, context->depth, CopyFromParent,
678
context->visual, mask, &attr);
679
/* XSetWindowColormap(dpy, context->drawable, attr.colormap);*/
685
if (!context->visual) {
686
if ((context->attribs->flags & RC_DefaultVisual)
687
|| !bestContext(dpy, screen_number, context)) {
688
context->visual = DefaultVisual(dpy, screen_number);
689
context->depth = DefaultDepth(dpy, screen_number);
690
context->cmap = DefaultColormap(dpy, screen_number);
691
context->drawable = RootWindow(dpy, screen_number);
692
context->black = BlackPixel(dpy, screen_number);
693
context->white = WhitePixel(dpy, screen_number);
694
context->vclass = context->visual->class;
698
gcv.function = GXcopy;
699
gcv.graphics_exposures = False;
700
context->copy_gc = XCreateGC(dpy, context->drawable, GCFunction
701
|GCGraphicsExposures, &gcv);
703
if (context->vclass == PseudoColor || context->vclass == StaticColor) {
704
if (!setupPseudoColorColormap(context)) {
708
} else if (context->vclass == GrayScale || context->vclass == StaticGray) {
709
context->colors = allocateGrayScale(context);
710
if (!context->colors) {
714
} else if (context->vclass == TrueColor) {
715
/* calc offsets to create a TrueColor pixel */
716
context->red_offset = count_offset(context->visual->red_mask);
717
context->green_offset = count_offset(context->visual->green_mask);
718
context->blue_offset = count_offset(context->visual->blue_mask);
719
/* disable dithering on 24 bits visuals */
720
if (context->depth >= 24)
721
context->attribs->render_mode = RBestMatchRendering;
725
/* check avaiability of MIT-SHM */
727
if (!(context->attribs->flags & RC_UseSharedMemory)) {
728
context->attribs->flags |= RC_UseSharedMemory;
729
context->attribs->use_shared_memory = True;
732
if (context->attribs->use_shared_memory) {
736
context->flags.use_shared_pixmap = 0;
738
if (!XShmQueryVersion(context->dpy, &major, &minor, &sharedPixmaps)) {
739
context->attribs->use_shared_memory = False;
741
if (XShmPixmapFormat(context->dpy)==ZPixmap)
742
context->flags.use_shared_pixmap = sharedPixmaps;
752
bestContext(Display *dpy, int screen_number, RContext *context)
754
XVisualInfo *vinfo=NULL, rvinfo;
755
int best = -1, numvis, i;
757
XSetWindowAttributes attr;
759
rvinfo.class = TrueColor;
760
rvinfo.screen = screen_number;
761
flags = VisualClassMask | VisualScreenMask;
763
vinfo = XGetVisualInfo(dpy, flags, &rvinfo, &numvis);
764
if (vinfo) { /* look for a TrueColor, 24-bit or more (pref 24) */
765
for (i=numvis-1, best = -1; i>=0; i--) {
766
if (vinfo[i].depth == 24) best = i;
767
else if (vinfo[i].depth>24 && best<0) best = i;
772
if (best == -1) { /* look for a DirectColor, 24-bit or more (pref 24) */
773
rvinfo.class = DirectColor;
774
if (vinfo) XFree((char *) vinfo);
775
vinfo = XGetVisualInfo(dpy, flags, &rvinfo, &numvis);
777
for (i=0, best = -1; i<numvis; i++) {
778
if (vinfo[i].depth == 24) best = i;
779
else if (vinfo[i].depth>24 && best<0) best = i;
785
context->visual = vinfo[best].visual;
786
context->depth = vinfo[best].depth;
787
context->vclass = vinfo[best].class;
788
getColormap(context, screen_number);
789
attr.colormap = context->cmap;
790
attr.override_redirect = True;
791
attr.border_pixel = 0;
793
XCreateWindow(dpy, RootWindow(dpy, screen_number),
794
1, 1, 1, 1, 0, context->depth,
795
CopyFromParent, context->visual,
796
CWBorderPixel|CWColormap|CWOverrideRedirect, &attr);
797
/* XSetWindowColormap(dpy, context->drawable, context->cmap);*/
799
if (vinfo) XFree((char *) vinfo);