#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/Xatom.h>
#endif
#include "glutint.h"
GLUTwindow *__glutCurrentWindow = NULL;
GLUTwindow **__glutWindowList = NULL;
int __glutWindowListSize = 0;
#if !defined(_WIN32)
GLUTstale *__glutStaleWindowList = NULL;
#endif
GLUTwindow *__glutMenuWindow = NULL;
void (*__glutFreeOverlayFunc) (GLUToverlay *);
XVisualInfo *(*__glutDetermineVisualFromString) (char *string, Bool * treatAsSingle,
Criterion * requiredCriteria, int nRequired, int requiredMask, void **fbc) = NULL;
static Criterion requiredWindowCriteria[] =
{
{LEVEL, EQ, 0},
{TRANSPARENT, EQ, 0}
};
static int numRequiredWindowCriteria = sizeof(requiredWindowCriteria) / sizeof(Criterion);
static int requiredWindowCriteriaMask = (1 << LEVEL) | (1 << TRANSPARENT);
static void
cleanWindowWorkList(GLUTwindow * window)
{
GLUTwindow **pEntry = &__glutWindowWorkList;
GLUTwindow *entry = __glutWindowWorkList;
while (entry) {
if (entry == window) {
*pEntry = entry->prevWorkWin;
return;
} else {
pEntry = &entry->prevWorkWin;
entry = *pEntry;
}
}
}
#if !defined(_WIN32)
static void
cleanStaleWindowList(GLUTwindow * window)
{
GLUTstale **pEntry = &__glutStaleWindowList;
GLUTstale *entry = __glutStaleWindowList;
while (entry) {
if (entry->window == window) {
*pEntry = entry->next;
free(entry);
return;
} else {
pEntry = &entry->next;
entry = *pEntry;
}
}
}
#endif
static GLUTwindow *__glutWindowCache = NULL;
GLUTwindow *
__glutGetWindow(Window win)
{
int i;
if (__glutWindowCache && (win == __glutWindowCache->win ||
(__glutWindowCache->overlay && win ==
__glutWindowCache->overlay->win))) {
return
__glutWindowCache;
}
for (i = 0; i < __glutWindowListSize; i++) {
if (__glutWindowList[i]) {
if (win == __glutWindowList[i]->win) {
__glutWindowCache = __glutWindowList[i];
return __glutWindowCache;
}
if (__glutWindowList[i]->overlay) {
if (win == __glutWindowList[i]->overlay->win) {
__glutWindowCache = __glutWindowList[i];
return __glutWindowCache;
}
}
}
}
#if !defined(_WIN32)
{
GLUTstale *entry;
for (entry = __glutStaleWindowList; entry; entry = entry->next) {
if (entry->win == win)
return entry->window;
}
}
#endif
return NULL;
}
int GLUTAPIENTRY
glutGetWindow(void)
{
if (__glutCurrentWindow) {
return __glutCurrentWindow->num + 1;
} else {
return 0;
}
}
void
__glutSetWindow(GLUTwindow * window)
{
__glutCurrentWindow = window;
MAKE_CURRENT_LAYER(__glutCurrentWindow);
#if !defined(_WIN32)
if (!__glutCurrentWindow->isDirect)
__glutPutOnWorkList(__glutCurrentWindow, GLUT_FINISH_WORK);
#endif
if (__glutDebug) {
__glutPutOnWorkList(__glutCurrentWindow, GLUT_DEBUG_WORK);
}
}
void GLUTAPIENTRY
glutSetWindow(int win)
{
GLUTwindow *window;
if (win < 1 || win > __glutWindowListSize) {
__glutWarning("glutSetWindow attempted on bogus window.");
return;
}
window = __glutWindowList[win - 1];
if (!window) {
__glutWarning("glutSetWindow attempted on bogus window.");
return;
}
__glutSetWindow(window);
}
static int
getUnusedWindowSlot(void)
{
int i;
for (i = 0; i < __glutWindowListSize; i++) {
if (!__glutWindowList[i]) {
return i;
}
}
__glutWindowListSize++;
if (__glutWindowList) {
__glutWindowList = (GLUTwindow **)
realloc(__glutWindowList,
__glutWindowListSize * sizeof(GLUTwindow *));
} else {
__glutWindowList = (GLUTwindow **)
malloc(sizeof(GLUTwindow *));
}
if (!__glutWindowList)
__glutFatalError("out of memory.");
__glutWindowList[__glutWindowListSize - 1] = NULL;
return __glutWindowListSize - 1;
}
static XVisualInfo *
getVisualInfoCI(unsigned int mode)
{
static int bufSizeList[] =
{16, 12, 8, 4, 2, 1, 0};
XVisualInfo *vi;
int list[32];
int i, n = 0;
assert(!__glutDisplayString);
list[n++] = GLX_BUFFER_SIZE;
list[n++] = 1;
if (GLUT_WIND_IS_DOUBLE(mode)) {
list[n++] = GLX_DOUBLEBUFFER;
}
if (GLUT_WIND_IS_STEREO(mode)) {
list[n++] = GLX_STEREO;
}
if (GLUT_WIND_HAS_DEPTH(mode)) {
list[n++] = GLX_DEPTH_SIZE;
list[n++] = 1;
}
if (GLUT_WIND_HAS_STENCIL(mode)) {
list[n++] = GLX_STENCIL_SIZE;
list[n++] = 1;
}
list[n] = (int) None;
for (i = 0; bufSizeList[i]; i++) {
list[1] = bufSizeList[i];
vi = glXChooseVisual(__glutDisplay,
__glutScreen, list);
if (vi)
return vi;
}
return NULL;
}
static XVisualInfo *
getVisualInfoRGB(unsigned int mode)
{
int list[32];
int n = 0;
assert(!__glutDisplayString);
list[n++] = GLX_RGBA;
list[n++] = GLX_RED_SIZE;
list[n++] = 1;
list[n++] = GLX_GREEN_SIZE;
list[n++] = 1;
list[n++] = GLX_BLUE_SIZE;
list[n++] = 1;
if (GLUT_WIND_HAS_ALPHA(mode)) {
list[n++] = GLX_ALPHA_SIZE;
list[n++] = 1;
}
if (GLUT_WIND_IS_DOUBLE(mode)) {
list[n++] = GLX_DOUBLEBUFFER;
}
if (GLUT_WIND_IS_STEREO(mode)) {
list[n++] = GLX_STEREO;
}
if (GLUT_WIND_HAS_DEPTH(mode)) {
list[n++] = GLX_DEPTH_SIZE;
list[n++] = 1;
}
if (GLUT_WIND_HAS_STENCIL(mode)) {
list[n++] = GLX_STENCIL_SIZE;
list[n++] = 1;
}
if (GLUT_WIND_HAS_ACCUM(mode)) {
list[n++] = GLX_ACCUM_RED_SIZE;
list[n++] = 1;
list[n++] = GLX_ACCUM_GREEN_SIZE;
list[n++] = 1;
list[n++] = GLX_ACCUM_BLUE_SIZE;
list[n++] = 1;
if (GLUT_WIND_HAS_ALPHA(mode)) {
list[n++] = GLX_ACCUM_ALPHA_SIZE;
list[n++] = 1;
}
}
#if defined(GLX_VERSION_1_1) && (defined(GLX_SGIS_multisample) || defined(GLX_ARB_multisample))
if (GLUT_WIND_IS_MULTISAMPLE(mode)) {
if (!__glutIsSupportedByGLX("GLX_SGIS_multisample") &&
!__glutIsSupportedByGLX("GLX_ARB_multisample"))
return NULL;
#if defined(GLX_ARB_multisample)
list[n++] = GLX_SAMPLES_ARB;
#elif defined(GLX_SGIS_multisample)
list[n++] = GLX_SAMPLES_SGIS;
#endif
list[n++] = 4;
}
#endif
list[n] = (int) None;
return glXChooseVisual(__glutDisplay,
__glutScreen, list);
}
#ifndef VisualIDMask
#define VisualIDMask 0
#endif
static XVisualInfo *
getVisualInfoID(int id)
{
XVisualInfo temp;
int count;
#if !defined(_WIN32)
temp.visualid = id;
#endif
return XGetVisualInfo(__glutDisplay, VisualIDMask, &temp, &count);
}
XVisualInfo *
__glutGetVisualInfo(unsigned int mode)
{
char *visStr;
if (GLUT_WIND_IS_LUMINANCE(mode))
return NULL;
visStr = getenv("GLUT_FORCE_VISUAL");
if (visStr) {
int id = atoi(visStr);
return getVisualInfoID(id);
}
if (GLUT_WIND_IS_RGB(mode))
return getVisualInfoRGB(mode);
else
return getVisualInfoCI(mode);
}
XVisualInfo *
__glutDetermineVisual(
unsigned int displayMode,
Bool * treatAsSingle,
XVisualInfo * (getVisualInfo) (unsigned int))
{
XVisualInfo *vis;
assert(!__glutDisplayString);
*treatAsSingle = GLUT_WIND_IS_SINGLE(displayMode);
vis = getVisualInfo(displayMode);
if (!vis) {
if (GLUT_WIND_IS_SINGLE(displayMode)) {
displayMode |= GLUT_DOUBLE;
vis = getVisualInfo(displayMode);
*treatAsSingle = True;
}
if (!vis && GLUT_WIND_IS_MULTISAMPLE(displayMode)) {
displayMode &= ~GLUT_MULTISAMPLE;
vis = getVisualInfo(displayMode);
}
}
return vis;
}
static void GLUTCALLBACK
__glutDefaultDisplay(void)
{
__glutWarning("The following is a new check for GLUT 3.0; update your code.");
__glutFatalError(
"redisplay needed for window %d, but no display callback.",
__glutCurrentWindow->num + 1);
}
void GLUTCALLBACK
__glutDefaultReshape(int width, int height)
{
GLUToverlay *overlay;
MAKE_CURRENT_WINDOW(__glutCurrentWindow);
glViewport(0, 0, (GLsizei) width, (GLsizei) height);
overlay = __glutCurrentWindow->overlay;
if (overlay) {
MAKE_CURRENT_OVERLAY(overlay);
glViewport(0, 0, (GLsizei) width, (GLsizei) height);
}
MAKE_CURRENT_LAYER(__glutCurrentWindow);
}
XVisualInfo *
__glutDetermineWindowVisual(Bool * treatAsSingle, Bool * visAlloced, void **fbc)
{
if (__glutDisplayString) {
assert(__glutDetermineVisualFromString);
*visAlloced = False;
*fbc = NULL;
return __glutDetermineVisualFromString(__glutDisplayString, treatAsSingle,
requiredWindowCriteria, numRequiredWindowCriteria, requiredWindowCriteriaMask, fbc);
} else {
*visAlloced = True;
*fbc = NULL;
return __glutDetermineVisual(__glutDisplayMode,
treatAsSingle, __glutGetVisualInfo);
}
}
GLUTwindow *
__glutCreateWindow(GLUTwindow * parent,
int x, int y, int width, int height, int gameMode)
{
GLUTwindow *window;
XSetWindowAttributes wa;
unsigned long attribMask;
int winnum;
int i;
void *fbc;
#if defined(_WIN32)
WNDCLASS wc;
int style;
if (!GetClassInfo(GetModuleHandle(NULL), "GLUT", &wc)) {
__glutOpenWin32Connection(NULL);
}
#else
if (!__glutDisplay) {
__glutOpenXConnection(NULL);
}
#endif
if (__glutGameModeWindow) {
__glutFatalError("cannot create windows in game mode.");
}
winnum = getUnusedWindowSlot();
window = (GLUTwindow *) malloc(sizeof(GLUTwindow));
if (!window) {
__glutFatalError("out of memory.");
}
window->num = winnum;
#if !defined(_WIN32)
window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
&window->visAlloced, &fbc);
if (!window->vis) {
__glutFatalError(
"visual with necessary capabilities not found.");
}
__glutSetupColormap(window->vis, &window->colormap, &window->cmap);
#endif
window->eventMask = StructureNotifyMask | ExposureMask;
attribMask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
wa.background_pixmap = None;
wa.border_pixel = 0;
wa.colormap = window->cmap;
wa.event_mask = window->eventMask;
if (parent) {
if (parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
wa.event_mask |= GLUT_HACK_STOP_PROPAGATE_MASK;
attribMask |= CWDontPropagate;
wa.do_not_propagate_mask = parent->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
} else {
wa.do_not_propagate_mask = 0;
}
window->width = width;
window->height = height;
window->forceReshape = True;
window->ignoreKeyRepeat = False;
#if defined(_WIN32)
__glutAdjustCoords(parent ? parent->win : NULL,
&x, &y, &width, &height);
if (parent) {
style = WS_CHILD;
} else {
if (gameMode) {
style = WS_POPUP | WS_MAXIMIZE;
} else {
style = WS_OVERLAPPEDWINDOW;
}
}
window->win = CreateWindow("GLUT", "GLUT",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
x, y, width, height, parent ? parent->win : __glutRoot,
NULL, GetModuleHandle(NULL), 0);
window->hdc = GetDC(window->win);
XHDC = window->hdc;
window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
&window->visAlloced, &fbc);
if (!window->vis) {
__glutFatalError(
"pixel format with necessary capabilities not found.");
}
if (!SetPixelFormat(window->hdc,
ChoosePixelFormat(window->hdc, window->vis),
window->vis)) {
__glutFatalError("SetPixelFormat failed during window create.");
}
__glutSetupColormap(window->vis, &window->colormap, &window->cmap);
if (parent) {
PostMessage(parent->win, WM_ACTIVATE, 0, 0);
}
window->renderDc = window->hdc;
#else
window->win = XCreateWindow(__glutDisplay,
parent == NULL ? __glutRoot : parent->win,
x, y, width, height, 0,
window->vis->depth, InputOutput, window->vis->visual,
attribMask, &wa);
#endif
window->renderWin = window->win;
#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
{
window->ctx = glXCreateContext(__glutDisplay, window->vis,
None, __glutTryDirect);
}
if (!window->ctx) {
__glutFatalError(
"failed to create OpenGL rendering context.");
}
window->renderCtx = window->ctx;
#if !defined(_WIN32)
window->isDirect = glXIsDirect(__glutDisplay, window->ctx);
if (__glutForceDirect) {
if (!window->isDirect)
__glutFatalError("direct rendering not possible.");
}
#endif
window->parent = parent;
if (parent) {
window->siblings = parent->children;
parent->children = window;
} else {
window->siblings = NULL;
}
window->overlay = NULL;
window->children = NULL;
window->display = __glutDefaultDisplay;
window->reshape = __glutDefaultReshape;
window->mouse = NULL;
window->motion = NULL;
window->passive = NULL;
window->entry = NULL;
window->keyboard = NULL;
window->keyboardUp = NULL;
window->windowStatus = NULL;
window->visibility = NULL;
window->special = NULL;
window->specialUp = NULL;
window->buttonBox = NULL;
window->dials = NULL;
window->spaceMotion = NULL;
window->spaceRotate = NULL;
window->spaceButton = NULL;
window->tabletMotion = NULL;
window->tabletButton = NULL;
#ifdef _WIN32
window->joystick = NULL;
window->joyPollInterval = 0;
#endif
window->tabletPos[0] = -1;
window->tabletPos[1] = -1;
window->shownState = 0;
window->visState = -1;
window->entryState = -1;
window->desiredConfMask = 0;
window->buttonUses = 0;
window->cursor = GLUT_CURSOR_INHERIT;
window->workMask = GLUT_MAP_WORK;
#ifdef _WIN32
if (gameMode) {
window->desiredMapState = GameModeState;
} else {
window->desiredMapState = NormalState;
}
#else
window->desiredMapState = NormalState;
#endif
window->prevWorkWin = __glutWindowWorkList;
__glutWindowWorkList = window;
for (i = 0; i < GLUT_MAX_MENUS; i++) {
window->menu[i] = 0;
}
__glutWindowList[winnum] = window;
__glutSetWindow(window);
__glutDetermineMesaSwapHackSupport();
if (window->treatAsSingle) {
glDrawBuffer(GL_FRONT);
glReadBuffer(GL_FRONT);
}
return window;
}
int GLUTAPIENTRY
glutCreateWindow(const char *title)
{
static int firstWindow = 1;
GLUTwindow *window;
#if !defined(_WIN32)
XWMHints *wmHints;
#endif
Window win;
XTextProperty textprop;
if (__glutGameModeWindow) {
__glutFatalError("cannot create windows in game mode.");
}
window = __glutCreateWindow(NULL,
__glutSizeHints.x, __glutSizeHints.y,
__glutInitWidth, __glutInitHeight,
0);
win = window->win;
textprop.value = (unsigned char *) title;
textprop.encoding = XA_STRING;
textprop.format = 8;
textprop.nitems = strlen(title);
#if defined(_WIN32)
SetWindowText(win, title);
if (__glutIconic) {
window->desiredMapState = IconicState;
}
#else
wmHints = XAllocWMHints();
wmHints->initial_state =
__glutIconic ? IconicState : NormalState;
wmHints->flags = StateHint;
XSetWMProperties(__glutDisplay, win, &textprop, &textprop,
firstWindow ? __glutArgv : NULL,
firstWindow ? __glutArgc : 0,
&__glutSizeHints, wmHints, NULL);
XFree(wmHints);
XSetWMProtocols(__glutDisplay, win, &__glutWMDeleteWindow, 1);
#endif
firstWindow = 0;
return window->num + 1;
}
#ifdef _WIN32
int GLUTAPIENTRY
__glutCreateWindowWithExit(const char *title, void (__cdecl *exitfunc)(int))
{
__glutExitFunc = exitfunc;
return glutCreateWindow(title);
}
#endif
int GLUTAPIENTRY
glutCreateSubWindow(int win, int x, int y, int width, int height)
{
GLUTwindow *window;
window = __glutCreateWindow(__glutWindowList[win - 1],
x, y, width, height, 0);
#if !defined(_WIN32)
{
GLUTwindow *toplevel;
toplevel = __glutToplevelOf(window);
if (toplevel->cmap != window->cmap) {
__glutPutOnWorkList(toplevel, GLUT_COLORMAP_WORK);
}
}
#endif
return window->num + 1;
}
void
__glutDestroyWindow(GLUTwindow * window,
GLUTwindow * initialWindow)
{
GLUTwindow **prev, *cur, *parent, *siblings;
cur = window->children;
while (cur) {
siblings = cur->siblings;
__glutDestroyWindow(cur, initialWindow);
cur = siblings;
}
parent = window->parent;
if (parent && parent == initialWindow->parent) {
prev = &parent->children;
cur = parent->children;
while (cur) {
if (cur == window) {
*prev = cur->siblings;
break;
}
prev = &(cur->siblings);
cur = cur->siblings;
}
}
if (window == __glutCurrentWindow) {
UNMAKE_CURRENT();
__glutCurrentWindow = NULL;
}
if (window->overlay) {
__glutFreeOverlayFunc(window->overlay);
}
XDestroyWindow(__glutDisplay, window->win);
glXDestroyContext(__glutDisplay, window->ctx);
if (window->colormap) {
__glutFreeColormap(window->colormap);
}
__glutWindowList[window->num] = NULL;
cleanWindowWorkList(window);
#if !defined(_WIN32)
cleanStaleWindowList(window);
#endif
if (__glutWindowCache == window)
__glutWindowCache = NULL;
if (window->visAlloced) {
XFree(window->vis);
}
if (window == __glutGameModeWindow) {
__glutCloseDownGameMode();
}
free(window);
}
void GLUTAPIENTRY
glutDestroyWindow(int win)
{
GLUTwindow *window = __glutWindowList[win - 1];
if (__glutMappedMenu && __glutMenuWindow == window) {
__glutFatalUsage("destroying menu window not allowed while menus in use");
}
#if !defined(_WIN32)
if (window->parent) {
__glutPutOnWorkList(__glutToplevelOf(window->parent),
GLUT_COLORMAP_WORK);
}
#endif
__glutDestroyWindow(window, window);
XFlush(__glutDisplay);
}
void
__glutChangeWindowEventMask(long eventMask, Bool add)
{
if (add) {
if ((__glutCurrentWindow->eventMask & eventMask) !=
eventMask) {
__glutCurrentWindow->eventMask |= eventMask;
__glutPutOnWorkList(__glutCurrentWindow,
GLUT_EVENT_MASK_WORK);
}
} else {
if (__glutCurrentWindow->eventMask & eventMask) {
__glutCurrentWindow->eventMask &= ~eventMask;
__glutPutOnWorkList(__glutCurrentWindow,
GLUT_EVENT_MASK_WORK);
}
}
}
void GLUTAPIENTRY
glutDisplayFunc(GLUTdisplayCB displayFunc)
{
if (!displayFunc)
__glutFatalError("NULL display callback not allowed in GLUT 3.0; update your code.");
__glutCurrentWindow->display = displayFunc;
}
void GLUTAPIENTRY
glutMouseFunc(GLUTmouseCB mouseFunc)
{
if (__glutCurrentWindow->mouse) {
if (!mouseFunc) {
__glutCurrentWindow->buttonUses--;
__glutChangeWindowEventMask(
ButtonPressMask | ButtonReleaseMask,
__glutCurrentWindow->buttonUses > 0);
}
} else {
if (mouseFunc) {
__glutCurrentWindow->buttonUses++;
__glutChangeWindowEventMask(
ButtonPressMask | ButtonReleaseMask, True);
}
}
__glutCurrentWindow->mouse = mouseFunc;
}
void GLUTAPIENTRY
glutMotionFunc(GLUTmotionCB motionFunc)
{
if (__glutCurrentWindow->motion) {
if (!motionFunc) {
__glutCurrentWindow->buttonUses--;
__glutChangeWindowEventMask(
ButtonPressMask | ButtonReleaseMask,
__glutCurrentWindow->buttonUses > 0);
}
} else {
if (motionFunc) {
__glutCurrentWindow->buttonUses++;
__glutChangeWindowEventMask(
ButtonPressMask | ButtonReleaseMask, True);
}
}
__glutChangeWindowEventMask(
Button1MotionMask | Button2MotionMask | Button3MotionMask,
motionFunc != NULL);
__glutCurrentWindow->motion = motionFunc;
}
void GLUTAPIENTRY
glutPassiveMotionFunc(GLUTpassiveCB passiveMotionFunc)
{
__glutChangeWindowEventMask(PointerMotionMask,
passiveMotionFunc != NULL);
__glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
__glutCurrentWindow->entry != NULL || passiveMotionFunc != NULL);
__glutCurrentWindow->passive = passiveMotionFunc;
}
void GLUTAPIENTRY
glutEntryFunc(GLUTentryCB entryFunc)
{
__glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
entryFunc != NULL || __glutCurrentWindow->passive);
__glutCurrentWindow->entry = entryFunc;
if (!entryFunc) {
__glutCurrentWindow->entryState = -1;
}
}
void GLUTAPIENTRY
glutWindowStatusFunc(GLUTwindowStatusCB windowStatusFunc)
{
__glutChangeWindowEventMask(VisibilityChangeMask,
windowStatusFunc != NULL);
__glutCurrentWindow->windowStatus = windowStatusFunc;
if (!windowStatusFunc) {
__glutCurrentWindow->visState = -1;
}
}
static void GLUTCALLBACK
visibilityHelper(int status)
{
if (status == GLUT_HIDDEN || status == GLUT_FULLY_COVERED)
__glutCurrentWindow->visibility(GLUT_NOT_VISIBLE);
else
__glutCurrentWindow->visibility(GLUT_VISIBLE);
}
void GLUTAPIENTRY
glutVisibilityFunc(GLUTvisibilityCB visibilityFunc)
{
__glutCurrentWindow->visibility = visibilityFunc;
if (visibilityFunc)
glutWindowStatusFunc(visibilityHelper);
else
glutWindowStatusFunc(NULL);
}
void GLUTAPIENTRY
glutReshapeFunc(GLUTreshapeCB reshapeFunc)
{
if (reshapeFunc) {
__glutCurrentWindow->reshape = reshapeFunc;
} else {
__glutCurrentWindow->reshape = __glutDefaultReshape;
}
}