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