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