Merge branch 'master' into gallium-0.2
[mesa.git] / src / glut / os2 / glut_cmap.cpp
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 //EK#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) && !defined(__OS2__)
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) || defined(__OS2__)
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) || defined(__OS2__)
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) && !defined(__OS2__)
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) || defined(__OS2__)
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 case DirectColor:
181 *colormap = NULL; /* NULL if RGBA */
182
183 /* Hewlett-Packard supports a feature called "HP Color
184 Recovery". Mesa has code to use HP Color Recovery. For
185 Mesa to use this feature, the atom
186 _HP_RGB_SMOOTH_MAP_LIST must be defined on the root
187 window AND the colormap obtainable by XGetRGBColormaps
188 for that atom must be set on the window. If that
189 colormap is not set, the output will look stripy. */
190
191 if (hpColorRecoveryAtom == -1) {
192 char *xvendor;
193
194 #define VENDOR_HP "Hewlett-Packard"
195
196 /* Only makes sense to make XInternAtom round-trip if we
197 know that we are connected to an HP X server. */
198 xvendor = ServerVendor(__glutDisplay);
199 if (!strncmp(xvendor, VENDOR_HP, sizeof(VENDOR_HP) - 1)) {
200 hpColorRecoveryAtom = XInternAtom(__glutDisplay, "_HP_RGB_SMOOTH_MAP_LIST", True);
201 } else {
202 hpColorRecoveryAtom = None;
203 }
204 }
205 if (hpColorRecoveryAtom != None) {
206 status = XGetRGBColormaps(__glutDisplay, __glutRoot,
207 &standardCmaps, &numCmaps, hpColorRecoveryAtom);
208 if (status == 1) {
209 for (i = 0; i < numCmaps; i++) {
210 if (standardCmaps[i].visualid == vi->visualid) {
211 *cmap = standardCmaps[i].colormap;
212 XFree(standardCmaps);
213 return;
214 }
215 }
216 XFree(standardCmaps);
217 }
218 }
219 #ifndef SOLARIS_2_4_BUG
220 /* Solaris 2.4 and 2.5 have a bug in their
221 XmuLookupStandardColormap implementations. Please
222 compile your Solaris 2.4 or 2.5 version of GLUT with
223 -DSOLARIS_2_4_BUG to work around this bug. The symptom
224 of the bug is that programs will get a BadMatch error
225 from X_CreateWindow when creating a GLUT window because
226 Solaris 2.4 and 2.5 create a corrupted RGB_DEFAULT_MAP
227 property. Note that this workaround prevents Colormap
228 sharing between applications, perhaps leading
229 unnecessary colormap installations or colormap flashing.
230 Sun fixed this bug in Solaris 2.6. */
231 status = XmuLookupStandardColormap(__glutDisplay,
232 vi->screen, vi->visualid, vi->depth, XA_RGB_DEFAULT_MAP,
233 /* replace */ False, /* retain */ True);
234 if (status == 1) {
235 status = XGetRGBColormaps(__glutDisplay, __glutRoot,
236 &standardCmaps, &numCmaps, XA_RGB_DEFAULT_MAP);
237 if (status == 1) {
238 for (i = 0; i < numCmaps; i++) {
239 if (standardCmaps[i].visualid == vi->visualid) {
240 *cmap = standardCmaps[i].colormap;
241 XFree(standardCmaps);
242 return;
243 }
244 }
245 XFree(standardCmaps);
246 }
247 }
248 #endif
249 /* If no standard colormap but TrueColor, just make a
250 private one. */
251 /* XXX Should do a better job of internal sharing for
252 privately allocated TrueColor colormaps. */
253 /* XXX DirectColor probably needs ramps hand initialized! */
254 *cmap = XCreateColormap(__glutDisplay, __glutRoot,
255 vi->visual, AllocNone);
256 break;
257 case StaticColor:
258 case StaticGray:
259 case GrayScale:
260 /* Mesa supports these visuals */
261 *colormap = NULL;
262 *cmap = XCreateColormap(__glutDisplay, __glutRoot,
263 vi->visual, AllocNone);
264 break;
265 default:
266 __glutFatalError(
267 "could not allocate colormap for visual type: %d.",
268 visualClass);
269 }
270 return;
271 #endif
272 }
273
274 #if !defined(_WIN32) && !defined(__OS2__)
275 static int
276 findColormaps(GLUTwindow * window,
277 Window * winlist, Colormap * cmaplist, int num, int max)
278 {
279 GLUTwindow *child;
280 int i;
281
282 /* Do not allow more entries that maximum number of
283 colormaps! */
284 if (num >= max)
285 return num;
286 /* Is cmap for this window already on the list? */
287 for (i = 0; i < num; i++) {
288 if (cmaplist[i] == window->cmap)
289 goto normalColormapAlreadyListed;
290 }
291 /* Not found on the list; add colormap and window. */
292 winlist[num] = window->win;
293 cmaplist[num] = window->cmap;
294 num++;
295
296 normalColormapAlreadyListed:
297
298 /* Repeat above but for the overlay colormap if there one. */
299 if (window->overlay) {
300 if (num >= max)
301 return num;
302 for (i = 0; i < num; i++) {
303 if (cmaplist[i] == window->overlay->cmap)
304 goto overlayColormapAlreadyListed;
305 }
306 winlist[num] = window->overlay->win;
307 cmaplist[num] = window->overlay->cmap;
308 num++;
309 }
310 overlayColormapAlreadyListed:
311
312 /* Recursively search children. */
313 child = window->children;
314 while (child) {
315 num = findColormaps(child, winlist, cmaplist, num, max);
316 child = child->siblings;
317 }
318 return num;
319 }
320
321 void
322 __glutEstablishColormapsProperty(GLUTwindow * window)
323 {
324 /* this routine is strictly X. Win32 doesn't need to do
325 anything of this sort (but has to do other wacky stuff
326 later). */
327 static Atom wmColormapWindows = None;
328 Window *winlist;
329 Colormap *cmaplist;
330 Status status;
331 int maxcmaps, num;
332
333 assert(!window->parent);
334 maxcmaps = MaxCmapsOfScreen(ScreenOfDisplay(__glutDisplay,
335 __glutScreen));
336 /* For portability reasons we don't use alloca for winlist
337 and cmaplist, but we could. */
338 winlist = (Window *) malloc(maxcmaps * sizeof(Window));
339 cmaplist = (Colormap *) malloc(maxcmaps * sizeof(Colormap));
340 num = findColormaps(window, winlist, cmaplist, 0, maxcmaps);
341 if (num < 2) {
342 /* Property no longer needed; remove it. */
343 wmColormapWindows = XSGIFastInternAtom(__glutDisplay,
344 "WM_COLORMAP_WINDOWS", SGI_XA_WM_COLORMAP_WINDOWS, False);
345 if (wmColormapWindows == None) {
346 __glutWarning("Could not intern X atom for WM_COLORMAP_WINDOWS.");
347 return;
348 }
349 XDeleteProperty(__glutDisplay, window->win, wmColormapWindows);
350 } else {
351 status = XSetWMColormapWindows(__glutDisplay, window->win,
352 winlist, num);
353 /* XSetWMColormapWindows should always work unless the
354 WM_COLORMAP_WINDOWS property cannot be intern'ed. We
355 check to be safe. */
356 if (status == False)
357 __glutFatalError("XSetWMColormapWindows returned False.");
358 }
359 /* For portability reasons we don't use alloca for winlist
360 and cmaplist, but we could. */
361 free(winlist);
362 free(cmaplist);
363 }
364
365 GLUTwindow *
366 __glutToplevelOf(GLUTwindow * window)
367 {
368 while (window->parent) {
369 window = window->parent;
370 }
371 return window;
372 }
373 #endif
374
375 void
376 __glutFreeColormap(GLUTcolormap * cmap)
377 {
378 GLUTcolormap *cur, **prev;
379
380 cmap->refcnt--;
381 if (cmap->refcnt == 0) {
382 /* remove from colormap list */
383 cur = __glutColormapList;
384 prev = &__glutColormapList;
385 while (cur) {
386 if (cur == cmap) {
387 *prev = cmap->next;
388 break;
389 }
390 prev = &(cur->next);
391 cur = cur->next;
392 }
393 /* actually free colormap */
394 XFreeColormap(__glutDisplay, cmap->cmap);
395 free(cmap->cells);
396 free(cmap);
397 }
398 }
399