bug fix in wbutton.c, made mouse pointer go invisible when typing in
[wmaker-crm.git] / wrlib / context.c
blob11bdafcdf75c7db78375127dcc0924e734b8f414
1 /* context.c - X context management
2 *
3 * Raster graphics library
4 *
5 * Copyright (c) 1997, 1998, 1999 Alfredo K. Kojima
6 *
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.
22 #include <config.h>
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <X11/Xatom.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <assert.h>
33 #include <math.h>
35 #include "wraster.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 RM_DITHER, /* render_mode */
46 4, /* colors_per_channel */
47 0,
51 True, /* use_shared_memory */
52 RMitchellFilter
56 static XColor*
57 allocatePseudoColor(RContext *ctx)
59 XColor *colors;
60 XColor avcolors[256];
61 int avncolors;
62 int i, ncolors, r, g, b;
63 int retries;
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);
77 if (!colors) {
78 RErrorCode = RERR_NOMEMORY;
79 return NULL;
81 i=0;
83 if ((ctx->attribs->flags & RC_GammaCorrection) && ctx->attribs->rgamma > 0
84 && ctx->attribs->ggamma > 0 && ctx->attribs->bgamma > 0) {
85 double rg, gg, bg;
86 double tmp;
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));
109 i++;
114 } else {
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;
122 i++;
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 */
131 } else {
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) {
144 int j;
145 unsigned long cdiff=0xffffffff, diff;
146 unsigned long closest=0;
148 retries = 2;
150 while (retries--) {
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;
157 if (diff<cdiff) {
158 cdiff = diff;
159 closest = j;
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 */
170 #ifdef DEBUG
171 printf("close color allocation failed. Retrying...\n");
172 #endif
176 return colors;
180 static XColor*
181 allocateGrayScale(RContext *ctx)
183 XColor *colors;
184 XColor avcolors[256];
185 int avncolors;
186 int i, ncolors, r, g, b;
187 int retries;
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;
195 } else {
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 = RM_MATCH;
210 colors = malloc(sizeof(XColor)*ncolors);
211 if (!colors) {
212 RErrorCode = RERR_NOMEMORY;
213 return False;
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++) {
223 #ifdef DEBUG
224 printf("trying:%x,%x,%x\n",colors[i].red,colors[i].green,colors[i].blue);
225 #endif
226 if (!XAllocColor(ctx->dpy, ctx->cmap, &(colors[i]))) {
227 colors[i].flags = 0; /* failed */
228 #ifdef DEBUG
229 printf("failed:%x,%x,%x\n",colors[i].red,colors[i].green,colors[i].blue);
230 #endif
231 } else {
232 colors[i].flags = DoRed|DoGreen|DoBlue;
233 #ifdef DEBUG
234 printf("success:%x,%x,%x\n",colors[i].red,colors[i].green,colors[i].blue);
235 #endif
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) {
247 int j;
248 unsigned long cdiff=0xffffffff, diff;
249 unsigned long closest=0;
251 retries = 2;
253 while (retries--) {
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;
260 if (diff<cdiff) {
261 cdiff = diff;
262 closest = j;
265 /* allocate closest color found */
266 #ifdef DEBUG
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);
268 #endif
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 */
276 #ifdef DEBUG
277 printf("close color allocation failed. Retrying...\n");
278 #endif
282 return colors;
286 static char*
287 mygetenv(char *var, int scr)
289 char *p;
290 char varname[64];
292 sprintf(varname, "%s%i", var, scr);
293 p = getenv(varname);
294 if (!p) {
295 p = getenv(var);
297 return p;
301 static void
302 gatherconfig(RContext *context, int screen_n)
304 char *ptr;
306 ptr = mygetenv("WRASTER_GAMMA", screen_n);
307 if (ptr) {
308 float g1,g2,g3;
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",
312 ptr);
313 } else {
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);
321 if (ptr) {
322 int i;
323 if (sscanf(ptr, "%d", &i)!=1 || i<2 || i>6) {
324 printf("wrlib: invalid value for color resolution \"%s\"\n",ptr);
325 } else {
326 context->attribs->flags |= RC_ColorsPerChannel;
327 context->attribs->colors_per_channel = i;
333 static void
334 getColormap(RContext *context, int screen_number)
336 Colormap cmap = None;
337 XStandardColormap *cmaps;
338 int ncmaps, i;
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) {
345 puts("ACHOU");
346 cmap = cmaps[i].colormap;
347 break;
350 XFree(cmaps);
352 if (cmap == None) {
353 XColor color;
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;
372 static int
373 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 RCreateContext(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 _wraster_change_filter(context->attribs->scaling_filter);
420 if ((context->attribs->flags & RC_VisualID)) {
421 XVisualInfo *vinfo, templ;
422 int nret;
424 templ.screen = screen_number;
425 templ.visualid = context->attribs->visualid;
426 vinfo = XGetVisualInfo(context->dpy, VisualIDMask|VisualScreenMask,
427 &templ, &nret);
428 if (!vinfo || nret==0) {
429 free(context);
430 RErrorCode = RERR_BADVISUALID;
431 return NULL;
434 if (vinfo[0].visual == DefaultVisual(dpy, screen_number)) {
435 context->attribs->flags |= RC_DefaultVisual;
436 } else {
437 XSetWindowAttributes attr;
438 unsigned long mask;
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;
449 context->drawable =
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);*/
455 XFree(vinfo);
458 /* use default */
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) {
480 return NULL;
482 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
483 context->colors = allocateGrayScale(context);
484 if (!context->colors) {
485 return NULL;
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 = RM_MATCH;
497 /* check avaiability of MIT-SHM */
498 #ifdef XSHM
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) {
505 int major, minor;
506 Bool sharedPixmaps;
508 context->flags.use_shared_pixmap = 0;
510 if (!XShmQueryVersion(context->dpy, &major, &minor, &sharedPixmaps)) {
511 context->attribs->use_shared_memory = False;
512 } else {
513 if (XShmPixmapFormat(context->dpy)==ZPixmap)
514 context->flags.use_shared_pixmap = sharedPixmaps;
517 #endif
519 return context;
523 static Bool
524 bestContext(Display *dpy, int screen_number, RContext *context)
526 XVisualInfo *vinfo=NULL, rvinfo;
527 int best = -1, numvis, i;
528 long flags;
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;
543 #if 0
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);
548 if (vinfo) {
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;
555 #endif
556 if (best > -1) {
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;
564 context->drawable =
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);
573 if (best < 0)
574 return False;
575 else
576 return True;