#ifdef __VMS
#include <GL/vms_x_fix.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#if !defined(_WIN32)
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#if defined (__vms)
#include <Xmu/StdCmap.h>
#else
#include <X11/Xmu/StdCmap.h>
#endif
#endif
#include "glutint.h"
#include "layerutil.h"
static Criterion requiredOverlayCriteria[] =
{
{LEVEL, EQ, 1},
{TRANSPARENT, EQ, 1},
{XPSEUDOCOLOR, EQ, 1},
{RGBA, EQ, 0},
{BUFFER_SIZE, GTE, 1}
};
static int numRequiredOverlayCriteria = sizeof(requiredOverlayCriteria) / sizeof(Criterion);
static int requiredOverlayCriteriaMask =
(1 << LEVEL) | (1 << TRANSPARENT) | (1 << XSTATICGRAY) | (1 << RGBA) | (1 << CI_MODE);
#if !defined(_WIN32)
static int
checkOverlayAcceptability(XVisualInfo * vi, unsigned int mode)
{
int value;
glXGetConfig(__glutDisplay, vi, GLX_USE_GL, &value);
if (!value)
return 1;
glXGetConfig(__glutDisplay, vi, GLX_RGBA, &value);
if (value)
return 1;
glXGetConfig(__glutDisplay, vi, GLX_DOUBLEBUFFER, &value);
if (GLUT_WIND_IS_DOUBLE(mode) != (value != 0))
return 1;
glXGetConfig(__glutDisplay, vi, GLX_STEREO, &value);
if (GLUT_WIND_IS_STEREO(mode) != (value != 0))
return 1;
if (GLUT_WIND_HAS_ALPHA(mode) || GLUT_WIND_HAS_ACCUM(mode))
return 1;
glXGetConfig(__glutDisplay, vi, GLX_DEPTH_SIZE, &value);
if (GLUT_WIND_HAS_DEPTH(mode) && (value <= 0))
return 1;
glXGetConfig(__glutDisplay, vi, GLX_STENCIL_SIZE, &value);
if (GLUT_WIND_HAS_STENCIL(mode) && (value <= 0))
return 1;
#if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
if (__glutIsSupportedByGLX("GLX_SGIS_multisample"))
glXGetConfig(__glutDisplay, vi, GLX_SAMPLES_SGIS, &value);
else
value = 0;
if (GLUT_WIND_IS_MULTISAMPLE(mode) && (value <= 0))
return 1;
#endif
return 0;
}
#endif
static XVisualInfo *
getOverlayVisualInfoCI(unsigned int mode)
{
#if !defined(_WIN32)
XLayerVisualInfo *vi;
XLayerVisualInfo template;
XVisualInfo *goodVisual, *returnVisual;
int nitems, i, j, bad;
for (i = 1; i <= 3; i++) {
template.vinfo.screen = __glutScreen;
template.vinfo.class = PseudoColor;
template.layer = i;
template.type = TransparentPixel;
vi = __glutXGetLayerVisualInfo(__glutDisplay,
VisualTransparentType | VisualScreenMask | VisualClassMask | VisualLayerMask,
&template, &nitems);
if (vi) {
for (j = 0; j < nitems; j++) {
bad = checkOverlayAcceptability(&vi[j].vinfo, mode);
if (bad) {
vi[j].vinfo.visual = NULL;
}
}
goodVisual = NULL;
for (j = 0; j < nitems; j++) {
if (vi[j].vinfo.visual) {
if (goodVisual == NULL) {
goodVisual = &vi[j].vinfo;
} else {
if (goodVisual->depth < vi[j].vinfo.depth) {
goodVisual = &vi[j].vinfo;
}
}
}
}
if (goodVisual) {
returnVisual = (XVisualInfo *) malloc(sizeof(XVisualInfo));
if (returnVisual) {
*returnVisual = *goodVisual;
}
XFree(vi);
return returnVisual;
}
XFree(vi);
}
}
#endif
return NULL;
}
static XVisualInfo *
getOverlayVisualInfoRGB(unsigned int mode)
{
__glutWarning("RGBA overlays are not supported by GLUT (for now).");
return NULL;
}
static XVisualInfo *
getOverlayVisualInfo(unsigned int mode)
{
if (GLUT_WIND_IS_LUMINANCE(mode))
return NULL;
if (GLUT_WIND_IS_RGB(mode))
return getOverlayVisualInfoRGB(mode);
else
return getOverlayVisualInfoCI(mode);
}
#if !defined(_WIN32)
static void
addStaleWindow(GLUTwindow * window, Window win)
{
GLUTstale *entry;
entry = (GLUTstale *) malloc(sizeof(GLUTstale));
if (!entry)
__glutFatalError("out of memory");
entry->window = window;
entry->win = win;
entry->next = __glutStaleWindowList;
__glutStaleWindowList = entry;
}
#endif
void
__glutFreeOverlay(GLUToverlay * overlay)
{
if (overlay->visAlloced)
XFree(overlay->vis);
XDestroyWindow(__glutDisplay, overlay->win);
glXDestroyContext(__glutDisplay, overlay->ctx);
if (overlay->colormap) {
__glutFreeColormap(overlay->colormap);
}
free(overlay);
}
static XVisualInfo *
determineOverlayVisual(int *treatAsSingle, Bool * visAlloced, void **fbc)
{
if (__glutDisplayString) {
XVisualInfo *vi;
int i;
assert(__glutDetermineVisualFromString);
*visAlloced = False;
*fbc = NULL;
for (i = 1; i <= 3; i++) {
requiredOverlayCriteria[0].value = i;
vi = __glutDetermineVisualFromString(__glutDisplayString, treatAsSingle,
requiredOverlayCriteria, numRequiredOverlayCriteria,
requiredOverlayCriteriaMask, fbc);
if (vi) {
return vi;
}
}
return NULL;
} else {
*visAlloced = True;
*fbc = NULL;
return __glutDetermineVisual(__glutDisplayMode,
treatAsSingle, getOverlayVisualInfo);
}
}
void GLUTAPIENTRY
glutEstablishOverlay(void)
{
GLUToverlay *overlay;
GLUTwindow *window;
XSetWindowAttributes wa;
void *fbc;
__glutFreeOverlayFunc = __glutFreeOverlay;
window = __glutCurrentWindow;
if (window->overlay) {
#if !defined(_WIN32)
addStaleWindow(window, window->overlay->win);
#endif
__glutFreeOverlay(window->overlay);
}
overlay = (GLUToverlay *) malloc(sizeof(GLUToverlay));
if (!overlay)
__glutFatalError("out of memory.");
overlay->vis = determineOverlayVisual(&overlay->treatAsSingle,
&overlay->visAlloced, &fbc);
if (!overlay->vis) {
__glutFatalError("lacks overlay support.");
}
#if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
if (fbc) {
window->ctx = __glut_glXCreateContextWithConfigSGIX(__glutDisplay, fbc,
GLX_RGBA_TYPE_SGIX, None, __glutTryDirect);
} else
#endif
{
overlay->ctx = glXCreateContext(__glutDisplay, overlay->vis,
None, __glutTryDirect);
}
if (!overlay->ctx) {
__glutFatalError(
"failed to create overlay OpenGL rendering context.");
}
#if !defined(_WIN32)
overlay->isDirect = glXIsDirect(__glutDisplay, overlay->ctx);
if (__glutForceDirect) {
if (!overlay->isDirect) {
__glutFatalError("direct rendering not possible.");
}
}
#endif
__glutSetupColormap(overlay->vis, &overlay->colormap, &overlay->cmap);
overlay->transparentPixel = __glutGetTransparentPixel(__glutDisplay,
overlay->vis);
wa.colormap = overlay->cmap;
wa.background_pixel = overlay->transparentPixel;
wa.event_mask = window->eventMask & GLUT_OVERLAY_EVENT_FILTER_MASK;
wa.border_pixel = 0;
#if defined(_WIN32)
#else
overlay->win = XCreateWindow(__glutDisplay,
window->win,
0, 0, window->width, window->height, 0,
overlay->vis->depth, InputOutput, overlay->vis->visual,
CWBackPixel | CWBorderPixel | CWEventMask | CWColormap,
&wa);
#endif
if (window->children) {
XLowerWindow(__glutDisplay, overlay->win);
}
XMapWindow(__glutDisplay, overlay->win);
overlay->shownState = 1;
overlay->display = NULL;
window->forceReshape = True;
#if !defined(_WIN32)
__glutPutOnWorkList(__glutToplevelOf(window), GLUT_COLORMAP_WORK);
#endif
window->overlay = overlay;
glutUseLayer(GLUT_OVERLAY);
if (overlay->treatAsSingle) {
glDrawBuffer(GL_FRONT);
glReadBuffer(GL_FRONT);
}
}
void GLUTAPIENTRY
glutRemoveOverlay(void)
{
GLUTwindow *window = __glutCurrentWindow;
GLUToverlay *overlay = __glutCurrentWindow->overlay;
if (!window->overlay)
return;
if (window->renderWin == overlay->win) {
glutUseLayer(GLUT_NORMAL);
}
#if !defined(_WIN32)
addStaleWindow(window, overlay->win);
#endif
__glutFreeOverlay(overlay);
window->overlay = NULL;
#if !defined(_WIN32)
__glutPutOnWorkList(__glutToplevelOf(window), GLUT_COLORMAP_WORK);
#endif
}
void GLUTAPIENTRY
glutUseLayer(GLenum layer)
{
GLUTwindow *window = __glutCurrentWindow;
switch (layer) {
case GLUT_NORMAL:
#ifdef _WIN32
window->renderDc = window->hdc;
#endif
window->renderWin = window->win;
window->renderCtx = window->ctx;
break;
case GLUT_OVERLAY:
#ifdef _WIN32
window->renderDc = window->overlay->hdc;
#endif
window->renderWin = window->overlay->win;
window->renderCtx = window->overlay->ctx;
break;
default:
__glutWarning("glutUseLayer: unknown layer, %d.", layer);
break;
}
__glutSetWindow(window);
}
void GLUTAPIENTRY
glutPostOverlayRedisplay(void)
{
__glutPostRedisplay(__glutCurrentWindow, GLUT_OVERLAY_REDISPLAY_WORK);
}
void GLUTAPIENTRY
glutPostWindowOverlayRedisplay(int win)
{
__glutPostRedisplay(__glutWindowList[win - 1], GLUT_OVERLAY_REDISPLAY_WORK);
}
void GLUTAPIENTRY
glutOverlayDisplayFunc(GLUTdisplayCB displayFunc)
{
if (!__glutCurrentWindow->overlay) {
__glutWarning("glutOverlayDisplayFunc: window has no overlay established");
return;
}
__glutCurrentWindow->overlay->display = displayFunc;
}
void GLUTAPIENTRY
glutHideOverlay(void)
{
if (!__glutCurrentWindow->overlay) {
__glutWarning("glutHideOverlay: window has no overlay established");
return;
}
XUnmapWindow(__glutDisplay, __glutCurrentWindow->overlay->win);
__glutCurrentWindow->overlay->shownState = 0;
}
void GLUTAPIENTRY
glutShowOverlay(void)
{
if (!__glutCurrentWindow->overlay) {
__glutWarning("glutShowOverlay: window has no overlay established");
return;
}
XMapWindow(__glutDisplay, __glutCurrentWindow->overlay->win);
__glutCurrentWindow->overlay->shownState = 1;
}
int GLUTAPIENTRY
glutLayerGet(GLenum param)
{
switch (param) {
case GLUT_OVERLAY_POSSIBLE:
{
XVisualInfo *vi;
Bool dummy, visAlloced;
void *fbc;
vi = determineOverlayVisual(&dummy, &visAlloced, &fbc);
if (vi) {
if (visAlloced)
XFree(vi);
return 1;
}
return 0;
}
case GLUT_LAYER_IN_USE:
return __glutCurrentWindow->renderWin != __glutCurrentWindow->win;
case GLUT_HAS_OVERLAY:
return __glutCurrentWindow->overlay != NULL;
case GLUT_TRANSPARENT_INDEX:
if (__glutCurrentWindow->overlay) {
return __glutCurrentWindow->overlay->transparentPixel;
} else {
return -1;
}
case GLUT_NORMAL_DAMAGED:
return (__glutCurrentWindow->workMask & GLUT_REPAIR_WORK)
|| __glutWindowDamaged;
case GLUT_OVERLAY_DAMAGED:
if (__glutCurrentWindow->overlay) {
return (__glutCurrentWindow->workMask & GLUT_OVERLAY_REPAIR_WORK)
|| __glutWindowDamaged;
} else {
return -1;
}
default:
__glutWarning("invalid glutLayerGet param: %d", param);
return -1;
}
}