
/* Copyright (c) Mark J. Kilgard, 1993, 1994, 2001. */

/* This program is freely distributable without licensing fees
   and is provided without guarantee or warrantee expressed or
   implied. This program is -not- in the public domain. */

/* Based on XLayerUtil.c: Revision: 1.5 */

#include <stdio.h>
#include <stdlib.h>
#include "layerutil.h"

/* SGI optimization introduced in IRIX 6.3 to avoid X server
   round trips for interning common X atoms. */
#include <X11/Xatom.h>
#if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
#include <X11/SGIFastAtom.h>
#else
#define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
#endif

static Bool layersRead = False;
static OverlayInfo **overlayInfoPerScreen;
static unsigned long *numOverlaysPerScreen;

static void
findServerOverlayVisualsInfo(Display * dpy)
{
  static Atom overlayVisualsAtom;
  Atom actualType;
  Status status;
  unsigned long sizeData, bytesLeft;
  Window root;
  int actualFormat, numScreens, i;

  if (layersRead == False) {
    overlayVisualsAtom = XSGIFastInternAtom(dpy,
      "SERVER_OVERLAY_VISUALS", SGI_XA_SERVER_OVERLAY_VISUALS, True);
    if (overlayVisualsAtom != None) {
      numScreens = ScreenCount(dpy);
      overlayInfoPerScreen = (OverlayInfo **)
        malloc(numScreens * sizeof(OverlayInfo *));
      numOverlaysPerScreen = (unsigned long *)
        malloc(numScreens * sizeof(unsigned long));
      if (overlayInfoPerScreen != NULL &&
        numOverlaysPerScreen != NULL) {
        for (i = 0; i < numScreens; i++) {
          root = RootWindow(dpy, i);
          status = XGetWindowProperty(dpy, root,
            overlayVisualsAtom, 0L, (long) 10000, False,
            overlayVisualsAtom, &actualType, &actualFormat,
            &sizeData, &bytesLeft,
            (unsigned char **) &overlayInfoPerScreen[i]);
          if (status != Success ||
            actualType != overlayVisualsAtom ||
            actualFormat != 32 || sizeData < 4) {
            numOverlaysPerScreen[i] = 0;
          } else {
            /* Four 32-bit quantities per
               SERVER_OVERLAY_VISUALS entry. */
            numOverlaysPerScreen[i] = sizeData / 4;
          }
        }
        layersRead = True;
      } else {
        if (overlayInfoPerScreen != NULL) {
          free(overlayInfoPerScreen);
        }
        if (numOverlaysPerScreen != NULL) {
          free(numOverlaysPerScreen);
        }
      }
    }
  }
}

int
__glutGetTransparentPixel(Display * dpy, XVisualInfo * vinfo)
{
  int i, screen = vinfo->screen;
  OverlayInfo *overlayInfo;

  findServerOverlayVisualsInfo(dpy);
  if (layersRead) {
    for (i = 0; i < numOverlaysPerScreen[screen]; i++) {
      overlayInfo = &overlayInfoPerScreen[screen][i];
      if (vinfo->visualid == overlayInfo->overlay_visual) {
        if (overlayInfo->transparent_type == TransparentPixel) {
          return (int) overlayInfo->value;
        } else {
          return -1;
        }
      }
    }
  }
  return -1;
}

XLayerVisualInfo *
__glutXGetLayerVisualInfo(Display * dpy, long lvinfo_mask,
  XLayerVisualInfo * lvinfo_template, int *nitems_return)
{
  XVisualInfo *vinfo;
  XLayerVisualInfo *layerInfo;
  int numVisuals, count, i, j;

  vinfo = XGetVisualInfo(dpy, lvinfo_mask & VisualAllMask,
    &lvinfo_template->vinfo, nitems_return);
  if (vinfo == NULL) {
    return NULL;
  }
  numVisuals = *nitems_return;
  findServerOverlayVisualsInfo(dpy);
  layerInfo = (XLayerVisualInfo *)
    malloc(numVisuals * sizeof(XLayerVisualInfo));
  if (layerInfo == NULL) {
    XFree(vinfo);
    return NULL;
  }
  count = 0;
  for (i = 0; i < numVisuals; i++) {
    XVisualInfo *pVinfo = &vinfo[i];
    int screen = pVinfo->screen;
    OverlayInfo *overlayInfo = NULL;

    overlayInfo = NULL;
    if (layersRead) {
      for (j = 0; j < numOverlaysPerScreen[screen]; j++) {
        if (pVinfo->visualid ==
          overlayInfoPerScreen[screen][j].overlay_visual) {
          overlayInfo = &overlayInfoPerScreen[screen][j];
          break;
        }
      }
    }
    if (lvinfo_mask & VisualLayerMask) {
      if (overlayInfo == NULL) {
        if (lvinfo_template->layer != 0) {
          continue;
        }
      } else if (lvinfo_template->layer != overlayInfo->layer) {
        continue;
      }
    }
    if (lvinfo_mask & VisualTransparentType) {
      if (overlayInfo == NULL) {
        if (lvinfo_template->type != None) {
          continue;
        }
      } else if (lvinfo_template->type !=
        overlayInfo->transparent_type) {
        continue;
      }
    }
    if (lvinfo_mask & VisualTransparentValue) {
      if (overlayInfo == NULL) {
        /* Non-overlay visuals have no sense of
           TransparentValue. */
        continue;
      } else if (lvinfo_template->value != overlayInfo->value) {
        continue;
      }
    }
    layerInfo[count].vinfo = *pVinfo;
    if (overlayInfo == NULL) {
      layerInfo[count].layer = 0;
      layerInfo[count].type = None;
      layerInfo[count].value = 0;  /* meaningless */
    } else {
      layerInfo[count].layer = overlayInfo->layer;
      layerInfo[count].type = overlayInfo->transparent_type;
      layerInfo[count].value = overlayInfo->value;
    }
    count++;
  }
  XFree(vinfo);
  *nitems_return = count;
  if (count == 0) {
    XFree(layerInfo);
    return NULL;
  } else {
    return layerInfo;
  }
}

#if 0                   /* Unused by GLUT. */
Status
__glutXMatchLayerVisualInfo(Display * dpy, int screen,
  int depth, int visualClass, int layer,
  XLayerVisualInfo * lvinfo_return)
{
  XLayerVisualInfo *lvinfo;
  XLayerVisualInfo lvinfoTemplate;
  int nitems;

  lvinfoTemplate.vinfo.screen = screen;
  lvinfoTemplate.vinfo.depth = depth;
#if defined(__cplusplus) || defined(c_plusplus)
  lvinfoTemplate.vinfo.c_class = visualClass;
#else
  lvinfoTemplate.vinfo.class = visualClass;
#endif
  lvinfoTemplate.layer = layer;
  lvinfo = __glutXGetLayerVisualInfo(dpy,
    VisualScreenMask | VisualDepthMask |
    VisualClassMask | VisualLayerMask,
    &lvinfoTemplate, &nitems);
  if (lvinfo != NULL && nitems > 0) {
    *lvinfo_return = *lvinfo;
    return 1;
  } else {
    return 0;
  }
}
#endif
