e6cb742cfec360ec05c2b1b9817e45c1b60b2cc4
[platform/upstream/mesa.git] / src / glut / glx / glut_cmap.c
1
2 /* Copyright (c) Mark J. Kilgard, 1994, 1996, 1997.  */
3
4 /* This program is freely distributable without licensing fees
5    and is provided without guarantee or warrantee expressed or
6    implied. This program is -not- in the public domain. */
7
8 #ifdef __VMS
9 #include <GL/vms_x_fix.h>
10 #endif
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <stdio.h>  /* SunOS multithreaded assert() needs <stdio.h>.  Lame. */
15 #include <assert.h>
16 #if !defined(_WIN32)
17 #include <X11/Xlib.h>
18 #include <X11/Xutil.h>
19 #include <X11/Xatom.h>  /* for XA_RGB_DEFAULT_MAP atom */
20 #if defined(__vms)
21 #include <Xmu/StdCmap.h>  /* for XmuLookupStandardColormap */
22 #else
23 #include <X11/Xmu/StdCmap.h>  /* for XmuLookupStandardColormap */
24 #endif
25 #endif
26
27 /* SGI optimization introduced in IRIX 6.3 to avoid X server
28    round trips for interning common X atoms. */
29 #if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
30 #include <X11/SGIFastAtom.h>
31 #else
32 #define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
33 #endif
34
35 #include "glutint.h"
36 #include "layerutil.h"
37
38 GLUTcolormap *__glutColormapList = NULL;
39
40 GLUTcolormap *
41 __glutAssociateNewColormap(XVisualInfo * vis)
42 {
43   GLUTcolormap *cmap;
44   int transparentPixel, i;
45   unsigned long pixels[255];
46
47   cmap = (GLUTcolormap *) malloc(sizeof(GLUTcolormap));
48   if (!cmap)
49     __glutFatalError("out of memory.");
50 #if defined(_WIN32)
51   pixels[0] = 0;        /* avoid compilation warnings on win32 */
52   cmap->visual = 0;
53   cmap->size = 256;     /* always assume 256 on Win32 */
54 #else
55   cmap->visual = vis->visual;
56   cmap->size = vis->visual->map_entries;
57 #endif
58   cmap->refcnt = 1;
59   cmap->cells = (GLUTcolorcell *)
60     malloc(sizeof(GLUTcolorcell) * cmap->size);
61   if (!cmap->cells)
62     __glutFatalError("out of memory.");
63   /* make all color cell entries be invalid */
64   for (i = cmap->size - 1; i >= 0; i--) {
65     cmap->cells[i].component[GLUT_RED] = -1.0;
66     cmap->cells[i].component[GLUT_GREEN] = -1.0;
67     cmap->cells[i].component[GLUT_BLUE] = -1.0;
68   }
69   transparentPixel = __glutGetTransparentPixel(__glutDisplay, vis);
70   if (transparentPixel == -1 || transparentPixel >= cmap->size) {
71
72     /* If there is no transparent pixel or if the transparent
73        pixel is outside the range of valid colormap cells (HP
74        can implement their overlays this smart way since their
75        transparent pixel is 255), we can AllocAll the colormap.
76        See note below.  */
77
78     cmap->cmap = XCreateColormap(__glutDisplay,
79       __glutRoot, cmap->visual, AllocAll);
80   } else {
81
82     /* On machines where zero (or some other value in the range
83        of 0 through map_entries-1), BadAlloc may be generated
84        when an AllocAll overlay colormap is allocated since the
85        transparent pixel precludes all the cells in the colormap
86        being allocated (the transparent pixel is pre-allocated).
87        So in this case, use XAllocColorCells to allocate
88        map_entries-1 pixels (that is, all but the transparent
89        pixel.  */
90
91 #if defined(_WIN32)
92     cmap->cmap = XCreateColormap(__glutDisplay,
93       __glutRoot, 0, AllocNone);
94 #else
95     cmap->cmap = XCreateColormap(__glutDisplay,
96       __glutRoot, vis->visual, AllocNone);
97     XAllocColorCells(__glutDisplay, cmap->cmap, False, 0, 0,
98       pixels, cmap->size - 1);
99 #endif
100   }
101   cmap->next = __glutColormapList;
102   __glutColormapList = cmap;
103   return cmap;
104 }
105
106 static GLUTcolormap *
107 associateColormap(XVisualInfo * vis)
108 {
109 #if !defined(_WIN32)
110   GLUTcolormap *cmap = __glutColormapList;
111
112   while (cmap != NULL) {
113     /* Play safe: compare visual IDs, not Visual*'s. */
114     if (cmap->visual->visualid == vis->visual->visualid) {
115       /* Already have created colormap for the visual. */
116       cmap->refcnt++;
117       return cmap;
118     }
119     cmap = cmap->next;
120   }
121 #endif
122   return __glutAssociateNewColormap(vis);
123 }
124
125 void
126 __glutSetupColormap(XVisualInfo * vi, GLUTcolormap ** colormap, Colormap * cmap)
127 {
128 #if defined(_WIN32)
129   if (vi->dwFlags & PFD_NEED_PALETTE || vi->iPixelType == PFD_TYPE_COLORINDEX) {
130     *colormap = associateColormap(vi);
131     *cmap = (*colormap)->cmap;
132   } else {
133     *colormap = NULL;
134     *cmap = 0;
135   }
136 #else
137   Status status;
138   XStandardColormap *standardCmaps;
139   int i, numCmaps;
140   static Atom hpColorRecoveryAtom = -1;
141   int isRGB, visualClass, rc;
142
143 #if defined(__cplusplus) || defined(c_plusplus)
144   visualClass = vi->c_class;
145 #else
146   visualClass = vi->class;
147 #endif
148   switch (visualClass) {
149   case PseudoColor:
150     /* Mesa might return a PseudoColor visual for RGB mode. */
151     rc = glXGetConfig(__glutDisplay, vi, GLX_RGBA, &isRGB);
152     if (rc == 0 && isRGB) {
153       /* Must be Mesa. */
154       *colormap = NULL;
155       if (MaxCmapsOfScreen(DefaultScreenOfDisplay(__glutDisplay)) == 1
156         && vi->visual == DefaultVisual(__glutDisplay, __glutScreen)) {
157         char *privateCmap = getenv("MESA_PRIVATE_CMAP");
158
159         if (privateCmap) {
160           /* User doesn't want to share colormaps. */
161           *cmap = XCreateColormap(__glutDisplay, __glutRoot,
162             vi->visual, AllocNone);
163         } else {
164           /* Share the root colormap. */
165           *cmap = DefaultColormap(__glutDisplay, __glutScreen);
166         }
167       } else {
168         /* Get our own PseudoColor colormap. */
169         *cmap = XCreateColormap(__glutDisplay, __glutRoot,
170           vi->visual, AllocNone);
171       }
172     } else {
173       /* CI mode, real GLX never returns a PseudoColor visual
174          for RGB mode. */
175       *colormap = associateColormap(vi);
176       *cmap = (*colormap)->cmap;
177     }
178     break;
179   case TrueColor:
180     *colormap = NULL;   /* NULL if RGBA */
181
182     /* Hewlett-Packard supports a feature called "HP Color
183        Recovery". Mesa has code to use HP Color Recovery.  For
184        Mesa to use this feature, the atom
185        _HP_RGB_SMOOTH_MAP_LIST must be defined on the root
186        window AND the colormap obtainable by XGetRGBColormaps
187        for that atom must be set on the window.  If that
188        colormap is not set, the output will look stripy. */
189
190     if (hpColorRecoveryAtom == -1) {
191       char *xvendor;
192
193 #define VENDOR_HP "Hewlett-Packard"
194
195       /* Only makes sense to make XInternAtom round-trip if we
196          know that we are connected to an HP X server. */
197       xvendor = ServerVendor(__glutDisplay);
198       if (!strncmp(xvendor, VENDOR_HP, sizeof(VENDOR_HP) - 1)) {
199         hpColorRecoveryAtom = XInternAtom(__glutDisplay, "_HP_RGB_SMOOTH_MAP_LIST", True);
200       } else {
201         hpColorRecoveryAtom = None;
202       }
203     }
204     if (hpColorRecoveryAtom != None) {
205       status = XGetRGBColormaps(__glutDisplay, __glutRoot,
206         &standardCmaps, &numCmaps, hpColorRecoveryAtom);
207       if (status == 1) {
208         for (i = 0; i < numCmaps; i++) {
209           if (standardCmaps[i].visualid == vi->visualid) {
210             *cmap = standardCmaps[i].colormap;
211             XFree(standardCmaps);
212             return;
213           }
214         }
215         XFree(standardCmaps);
216       }
217     }
218 #ifndef SOLARIS_2_4_BUG
219     /* Solaris 2.4 and 2.5 have a bug in their
220        XmuLookupStandardColormap implementations.  Please
221        compile your Solaris 2.4 or 2.5 version of GLUT with
222        -DSOLARIS_2_4_BUG to work around this bug. The symptom
223        of the bug is that programs will get a BadMatch error
224        from X_CreateWindow when creating a GLUT window because
225        Solaris 2.4 and 2.5 create a  corrupted RGB_DEFAULT_MAP
226        property.  Note that this workaround prevents Colormap
227        sharing between applications, perhaps leading
228        unnecessary colormap installations or colormap flashing.
229        Sun fixed this bug in Solaris 2.6. */
230     status = XmuLookupStandardColormap(__glutDisplay,
231       vi->screen, vi->visualid, vi->depth, XA_RGB_DEFAULT_MAP,
232       /* replace */ False, /* retain */ True);
233     if (status == 1) {
234       status = XGetRGBColormaps(__glutDisplay, __glutRoot,
235         &standardCmaps, &numCmaps, XA_RGB_DEFAULT_MAP);
236       if (status == 1) {
237         for (i = 0; i < numCmaps; i++) {
238           if (standardCmaps[i].visualid == vi->visualid) {
239             *cmap = standardCmaps[i].colormap;
240             XFree(standardCmaps);
241             return;
242           }
243         }
244         XFree(standardCmaps);
245       }
246     }
247 #endif
248     /* If no standard colormap but TrueColor, just make a
249        private one. */
250     /* XXX Should do a better job of internal sharing for
251        privately allocated TrueColor colormaps. */
252     *cmap = XCreateColormap(__glutDisplay, __glutRoot,
253       vi->visual, AllocNone);
254     break;
255   case DirectColor:
256     *colormap = NULL;   /* NULL if RGBA */
257     *cmap = XCreateColormap(__glutDisplay, __glutRoot,
258                             vi->visual, AllocAll);
259     if (vi->depth == 24) {
260       /* init the red, green, blue maps to linear ramps */
261       XColor xc[256];
262       int i;
263       for (i = 0; i < 256; i++) {
264         xc[i].pixel = (i << 16) | (i << 8) | i;
265         xc[i].red = (i << 8) | i;
266         xc[i].green = (i << 8) | i;
267         xc[i].blue = (i << 8) | i;
268         xc[i].flags = DoRed | DoGreen | DoBlue;
269       }
270       XStoreColors(__glutDisplay, *cmap, xc, 256);
271     }
272     else {
273        fprintf(stderr, "GLUT Error: DirectColor visuals other than 24-bits "
274                "not fully supported.\n");
275     }
276     break;
277   case StaticColor:
278   case StaticGray:
279   case GrayScale:
280     /* Mesa supports these visuals */
281     *colormap = NULL;
282     *cmap = XCreateColormap(__glutDisplay, __glutRoot,
283       vi->visual, AllocNone);
284     break;
285   default:
286     __glutFatalError(
287       "could not allocate colormap for visual type: %d.",
288       visualClass);
289   }
290   return;
291 #endif
292 }
293
294 #if !defined(_WIN32)
295 static int
296 findColormaps(GLUTwindow * window,
297   Window * winlist, Colormap * cmaplist, int num, int max)
298 {
299   GLUTwindow *child;
300   int i;
301
302   /* Do not allow more entries that maximum number of
303      colormaps! */
304   if (num >= max)
305     return num;
306   /* Is cmap for this window already on the list? */
307   for (i = 0; i < num; i++) {
308     if (cmaplist[i] == window->cmap)
309       goto normalColormapAlreadyListed;
310   }
311   /* Not found on the list; add colormap and window. */
312   winlist[num] = window->win;
313   cmaplist[num] = window->cmap;
314   num++;
315
316 normalColormapAlreadyListed:
317
318   /* Repeat above but for the overlay colormap if there one. */
319   if (window->overlay) {
320     if (num >= max)
321       return num;
322     for (i = 0; i < num; i++) {
323       if (cmaplist[i] == window->overlay->cmap)
324         goto overlayColormapAlreadyListed;
325     }
326     winlist[num] = window->overlay->win;
327     cmaplist[num] = window->overlay->cmap;
328     num++;
329   }
330 overlayColormapAlreadyListed:
331
332   /* Recursively search children. */
333   child = window->children;
334   while (child) {
335     num = findColormaps(child, winlist, cmaplist, num, max);
336     child = child->siblings;
337   }
338   return num;
339 }
340
341 void
342 __glutEstablishColormapsProperty(GLUTwindow * window)
343 {
344   /* this routine is strictly X.  Win32 doesn't need to do
345      anything of this sort (but has to do other wacky stuff
346      later). */
347   static Atom wmColormapWindows = None;
348   Window *winlist;
349   Colormap *cmaplist;
350   Status status;
351   int maxcmaps, num, i;
352
353   assert(!window->parent);
354   maxcmaps = MaxCmapsOfScreen(ScreenOfDisplay(__glutDisplay,
355       __glutScreen));
356   /* For portability reasons we don't use alloca for winlist
357      and cmaplist, but we could. */
358   winlist = (Window *) malloc(maxcmaps * sizeof(Window));
359   cmaplist = (Colormap *) malloc(maxcmaps * sizeof(Colormap));
360   for (i = 0; i < maxcmaps; i++) {
361     cmaplist[i] = 0;
362   }
363   num = findColormaps(window, winlist, cmaplist, 0, maxcmaps);
364   if (num < 2) {
365     /* Property no longer needed; remove it. */
366     wmColormapWindows = XSGIFastInternAtom(__glutDisplay,
367       "WM_COLORMAP_WINDOWS", SGI_XA_WM_COLORMAP_WINDOWS, False);
368     if (wmColormapWindows == None) {
369       __glutWarning("Could not intern X atom for WM_COLORMAP_WINDOWS.");
370       return;
371     }
372     XDeleteProperty(__glutDisplay, window->win, wmColormapWindows);
373   } else {
374     status = XSetWMColormapWindows(__glutDisplay, window->win,
375       winlist, num);
376     /* XSetWMColormapWindows should always work unless the
377        WM_COLORMAP_WINDOWS property cannot be intern'ed.  We
378        check to be safe. */
379     if (status == False)
380       __glutFatalError("XSetWMColormapWindows returned False.");
381   }
382   /* For portability reasons we don't use alloca for winlist
383      and cmaplist, but we could. */
384   free(winlist);
385   free(cmaplist);
386 }
387
388 GLUTwindow *
389 __glutToplevelOf(GLUTwindow * window)
390 {
391   while (window->parent) {
392     window = window->parent;
393   }
394   return window;
395 }
396 #endif
397
398 void
399 __glutFreeColormap(GLUTcolormap * cmap)
400 {
401   GLUTcolormap *cur, **prev;
402
403   cmap->refcnt--;
404   if (cmap->refcnt == 0) {
405     /* remove from colormap list */
406     cur = __glutColormapList;
407     prev = &__glutColormapList;
408     while (cur) {
409       if (cur == cmap) {
410         *prev = cmap->next;
411         break;
412       }
413       prev = &(cur->next);
414       cur = cur->next;
415     }
416     /* actually free colormap */
417     XFreeColormap(__glutDisplay, cmap->cmap);
418     free(cmap->cells);
419     free(cmap);
420   }
421 }
422