glut: Include X11 headers and libraries in SCons build.
[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