mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-18 15:58:06 +02:00
1220 lines
34 KiB
C++
1220 lines
34 KiB
C++
|
|
/* Copyright (c) Mark J. Kilgard, 1994, 1997. */
|
|
|
|
/* 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. */
|
|
|
|
#ifdef __VMS
|
|
#include <GL/vms_x_fix.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#if defined(__OS2__)
|
|
#define POKA 0
|
|
#include "WarpGL.h"
|
|
#include "glutos2.h"
|
|
#include "glutint.h"
|
|
|
|
#include "gl\os2mesa.h"
|
|
|
|
//
|
|
//define for resource id for main GLUT window, in samples it is defined in GL_TEST.h
|
|
#define ID_WINDOW 256
|
|
|
|
int evglSetPixelFormat(int iPixelFormat);
|
|
HPS hpsCurrent;
|
|
|
|
#elif !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) && !defined(__OS2__)
|
|
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;
|
|
|
|
/* Tranverse singly-linked window work list look for the
|
|
window. */
|
|
while (entry) {
|
|
if (entry == window) {
|
|
/* Found it; delete it. */
|
|
*pEntry = entry->prevWorkWin;
|
|
return;
|
|
} else {
|
|
pEntry = &entry->prevWorkWin;
|
|
entry = *pEntry;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if !defined(_WIN32) && !defined(__OS2PM__)
|
|
|
|
static void
|
|
cleanStaleWindowList(GLUTwindow * window)
|
|
{
|
|
GLUTstale **pEntry = &__glutStaleWindowList;
|
|
GLUTstale *entry = __glutStaleWindowList;
|
|
|
|
/* Tranverse singly-linked stale window list look for the
|
|
window ID. */
|
|
while (entry) {
|
|
if (entry->window == window) {
|
|
/* Found it; delete it. */
|
|
*pEntry = entry->next;
|
|
free(entry);
|
|
return;
|
|
} else {
|
|
pEntry = &entry->next;
|
|
entry = *pEntry;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
static GLUTwindow *__glutWindowCache = NULL;
|
|
|
|
GLUTwindow *
|
|
__glutGetWindow(Window win)
|
|
{
|
|
int i;
|
|
|
|
/* Does win belong to the last window ID looked up? */
|
|
if (__glutWindowCache && (win == __glutWindowCache->win ||
|
|
(__glutWindowCache->overlay && win ==
|
|
__glutWindowCache->overlay->win))) {
|
|
return
|
|
__glutWindowCache;
|
|
}
|
|
/* Otherwise scan the window list looking for the window ID. */
|
|
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) && !defined(__OS2PM__)
|
|
{
|
|
GLUTstale *entry;
|
|
|
|
/* Scan through destroyed overlay window IDs for which no
|
|
DestroyNotify has yet been received. */
|
|
for (entry = __glutStaleWindowList; entry; entry = entry->next) {
|
|
if (entry->win == win)
|
|
return entry->window;
|
|
}
|
|
}
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
/* CENTRY */
|
|
int GLUTAPIENTRY
|
|
glutGetWindow(void)
|
|
{
|
|
if (__glutCurrentWindow) {
|
|
return __glutCurrentWindow->num + 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
/* ENDCENTRY */
|
|
|
|
void
|
|
__glutSetWindow(GLUTwindow * window)
|
|
{
|
|
/* It is tempting to try to short-circuit the call to
|
|
glXMakeCurrent if we "know" we are going to make current
|
|
to a window we are already current to. In fact, this
|
|
assumption breaks when GLUT is expected to integrated with
|
|
other OpenGL windowing APIs that also make current to
|
|
OpenGL contexts. Since glXMakeCurrent short-circuits the
|
|
"already bound" case, GLUT avoids the temptation to do so
|
|
too. */
|
|
__glutCurrentWindow = window;
|
|
|
|
MAKE_CURRENT_LAYER(__glutCurrentWindow);
|
|
|
|
#if !defined(_WIN32) && !defined(__OS2__)
|
|
/* We should be careful to force a finish between each
|
|
iteration through the GLUT main loop if indirect OpenGL
|
|
contexts are in use; indirect contexts tend to have much
|
|
longer latency because lots of OpenGL extension requests
|
|
can queue up in the X protocol stream. We accomplish this
|
|
by posting GLUT_FINISH_WORK to be done. */
|
|
if (!__glutCurrentWindow->isDirect)
|
|
__glutPutOnWorkList(__glutCurrentWindow, GLUT_FINISH_WORK);
|
|
#endif
|
|
|
|
/* If debugging is enabled, we'll want to check this window
|
|
for any OpenGL errors every iteration through the GLUT
|
|
main loop. To accomplish this, we post the
|
|
GLUT_DEBUG_WORK to be done on this window. */
|
|
if (__glutDebug) {
|
|
__glutPutOnWorkList(__glutCurrentWindow, GLUT_DEBUG_WORK);
|
|
}
|
|
}
|
|
|
|
/* CENTRY */
|
|
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);
|
|
}
|
|
/* ENDCENTRY */
|
|
|
|
static int
|
|
getUnusedWindowSlot(void)
|
|
{
|
|
int i;
|
|
|
|
/* Look for allocated, unused slot. */
|
|
for (i = 0; i < __glutWindowListSize; i++) {
|
|
if (!__glutWindowList[i]) {
|
|
return i;
|
|
}
|
|
}
|
|
/* Allocate a new slot. */
|
|
__glutWindowListSize++;
|
|
if (__glutWindowList) {
|
|
__glutWindowList = (GLUTwindow **)
|
|
realloc(__glutWindowList,
|
|
__glutWindowListSize * sizeof(GLUTwindow *));
|
|
} else {
|
|
/* XXX Some realloc's do not correctly perform a malloc
|
|
when asked to perform a realloc on a NULL pointer,
|
|
though the ANSI C library spec requires this. */
|
|
__glutWindowList = (GLUTwindow **)
|
|
malloc(sizeof(GLUTwindow *));
|
|
}
|
|
if (!__glutWindowList)
|
|
__glutFatalError("out of memory.");
|
|
__glutWindowList[__glutWindowListSize - 1] = NULL;
|
|
return __glutWindowListSize - 1;
|
|
}
|
|
|
|
static XVisualInfo *
|
|
getVisualInfoCI(unsigned int mode)
|
|
{
|
|
#if POKA
|
|
static int bufSizeList[] =
|
|
{16, 12, 8, 4, 2, 1, 0};
|
|
XVisualInfo *vi;
|
|
int list[32];
|
|
int i, n = 0;
|
|
|
|
/* Should not be looking at display mode mask if
|
|
__glutDisplayString is non-NULL. */
|
|
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; /* terminate list */
|
|
|
|
/* glXChooseVisual specify GLX_BUFFER_SIZE prefers the
|
|
"smallest index buffer of at least the specified size".
|
|
This would be reasonable if GLUT allowed the user to
|
|
specify the required buffe size, but GLUT's display mode
|
|
is too simplistic (easy to use?). GLUT should try to find
|
|
the "largest". So start with a large buffer size and
|
|
shrink until we find a matching one that exists. */
|
|
|
|
for (i = 0; bufSizeList[i]; i++) {
|
|
/* XXX Assumes list[1] is where GLX_BUFFER_SIZE parameter
|
|
is. */
|
|
list[1] = bufSizeList[i];
|
|
vi = glXChooseVisual(__glutDisplay,
|
|
__glutScreen, list);
|
|
if (vi)
|
|
return vi;
|
|
}
|
|
return NULL;
|
|
#else
|
|
return
|
|
glXChooseVisual(mode);
|
|
|
|
#endif
|
|
}
|
|
|
|
static XVisualInfo *
|
|
getVisualInfoRGB(unsigned int mode)
|
|
{
|
|
#if POKA
|
|
int list[32];
|
|
int n = 0;
|
|
|
|
/* Should not be looking at display mode mask if
|
|
__glutDisplayString is non-NULL. */
|
|
assert(!__glutDisplayString);
|
|
|
|
/* XXX Would a caching mechanism to minize the calls to
|
|
glXChooseVisual? You'd have to reference count
|
|
XVisualInfo* pointers. Would also have to properly
|
|
interact with glutInitDisplayString. */
|
|
|
|
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
|
|
/* XXX Is 4 a reasonable minimum acceptable number of
|
|
samples? */
|
|
list[n++] = 4;
|
|
}
|
|
#endif
|
|
list[n] = (int) None; /* terminate list */
|
|
|
|
return glXChooseVisual(__glutDisplay,
|
|
__glutScreen, list);
|
|
#else /* POKA */
|
|
|
|
return
|
|
glXChooseVisual(mode);
|
|
|
|
#endif
|
|
}
|
|
|
|
XVisualInfo *
|
|
__glutGetVisualInfo(unsigned int mode)
|
|
{
|
|
/* XXX GLUT_LUMINANCE not implemented for GLUT 3.0. */
|
|
if (GLUT_WIND_IS_LUMINANCE(mode))
|
|
return NULL;
|
|
|
|
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;
|
|
|
|
/* Should not be looking at display mode mask if
|
|
__glutDisplayString is non-NULL. */
|
|
assert(!__glutDisplayString);
|
|
|
|
*treatAsSingle = GLUT_WIND_IS_SINGLE(displayMode);
|
|
vis = getVisualInfo(displayMode);
|
|
if (!vis) {
|
|
/* Fallback cases when can't get exactly what was asked
|
|
for... */
|
|
if (GLUT_WIND_IS_SINGLE(displayMode)) {
|
|
/* If we can't find a single buffered visual, try looking
|
|
for a double buffered visual. We can treat a double
|
|
buffered visual as a single buffer visual by changing
|
|
the draw buffer to GL_FRONT and treating any swap
|
|
buffers as no-ops. */
|
|
displayMode |= GLUT_DOUBLE;
|
|
vis = getVisualInfo(displayMode);
|
|
*treatAsSingle = True;
|
|
}
|
|
if (!vis && GLUT_WIND_IS_MULTISAMPLE(displayMode)) {
|
|
/* If we can't seem to get multisampling (ie, not Reality
|
|
Engine class graphics!), go without multisampling. It
|
|
is up to the application to query how many multisamples
|
|
were allocated (0 equals no multisampling) if the
|
|
application is going to use multisampling for more than
|
|
just antialiasing. */
|
|
displayMode &= ~GLUT_MULTISAMPLE;
|
|
vis = getVisualInfo(displayMode);
|
|
}
|
|
}
|
|
return vis;
|
|
}
|
|
|
|
static void GLUTCALLBACK
|
|
__glutDefaultDisplay(void)
|
|
{
|
|
/* XXX Remove the warning after GLUT 3.0. */
|
|
__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;
|
|
|
|
/* Adjust the viewport of the window (and overlay if one
|
|
exists). */
|
|
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 sure we are current to the current layer (application
|
|
should be able to count on the current layer not changing
|
|
unless the application explicitly calls glutUseLayer). */
|
|
MAKE_CURRENT_LAYER(__glutCurrentWindow);
|
|
}
|
|
|
|
XVisualInfo *
|
|
__glutDetermineWindowVisual(Bool * treatAsSingle, Bool * visAlloced, void **fbc)
|
|
{
|
|
if (__glutDisplayString) {
|
|
|
|
/* __glutDisplayString should be NULL except if
|
|
glutInitDisplayString has been called to register a
|
|
different display string. Calling glutInitDisplayString
|
|
means using a string instead of an integer mask determine
|
|
the visual to use. Using the function pointer variable
|
|
__glutDetermineVisualFromString below avoids linking in
|
|
the code for implementing glutInitDisplayString (ie,
|
|
glut_dstr.o) unless glutInitDisplayString gets called by
|
|
the application. */
|
|
|
|
assert(__glutDetermineVisualFromString);
|
|
*visAlloced = False;
|
|
*fbc = NULL;
|
|
return __glutDetermineVisualFromString(__glutDisplayString, treatAsSingle,
|
|
requiredWindowCriteria, numRequiredWindowCriteria, requiredWindowCriteriaMask, fbc);
|
|
} else {
|
|
*visAlloced = True;
|
|
*fbc = NULL;
|
|
return __glutDetermineVisual(__glutDisplayMode,
|
|
treatAsSingle, __glutGetVisualInfo);
|
|
}
|
|
}
|
|
|
|
/* ARGSUSED5 */ /* Only Win32 uses gameMode parameter. */
|
|
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;
|
|
#if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
|
|
GLXFBConfigSGIX fbc;
|
|
#else
|
|
void *fbc;
|
|
#endif
|
|
|
|
#if defined(__OS2PM__)
|
|
{
|
|
extern HAB hab; /* PM anchor block handle */
|
|
CLASSINFO classinfo;
|
|
|
|
if(!WinQueryClassInfo(hab,"GLUT", &classinfo) )
|
|
__glutOpenOS2Connection(NULL);
|
|
}
|
|
#elif defined(_WIN32)
|
|
WNDCLASS wc;
|
|
int style;
|
|
|
|
if (!GetClassInfo(GetModuleHandle(NULL), "GLUT", &wc)) {
|
|
__glutOpenWin32Connection(NULL);
|
|
}
|
|
#else
|
|
if (!__glutDisplay) {
|
|
__glutOpenXConnection(NULL);
|
|
}
|
|
#endif
|
|
|
|
#ifndef __OS2PM__
|
|
if (__glutGameModeWindow) {
|
|
__glutFatalError("cannot create windows in game mode.");
|
|
}
|
|
#endif
|
|
|
|
winnum = getUnusedWindowSlot();
|
|
window = (GLUTwindow *) malloc(sizeof(GLUTwindow));
|
|
if (!window) {
|
|
__glutFatalError("out of memory.");
|
|
}
|
|
window->num = winnum;
|
|
|
|
#if defined(__OS2PM__)
|
|
/* Add this new window to the window list. */
|
|
__glutWindowList[winnum] = window;
|
|
window->shownState = -1;
|
|
#endif
|
|
|
|
#if !defined(_WIN32) && !defined(__OS2PM__)
|
|
window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
|
|
&window->visAlloced, (void**) &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;
|
|
}
|
|
|
|
/* Stash width and height before Win32's __glutAdjustCoords
|
|
possibly overwrites the values. */
|
|
window->width = width;
|
|
window->height = height;
|
|
window->forceReshape = True;
|
|
window->ignoreKeyRepeat = False;
|
|
|
|
#if defined(__OS2PM__)
|
|
|
|
{ ULONG flStyle=0;
|
|
int ii;
|
|
ERRORID erridErrorCode;/* last error id code */
|
|
extern HAB hab; /* PM anchor block handle */
|
|
|
|
if (parent) {
|
|
flStyle = WS_CLIPCHILDREN|WS_VISIBLE;
|
|
} else {
|
|
if (gameMode) {
|
|
/* Game mode window should be a WS_POPUP window to
|
|
ensure that the taskbar is hidden by it. A standard
|
|
WS_OVERLAPPEDWINDOW does not hide the task bar. */
|
|
flStyle = FCF_STANDARD | WS_MAXIMIZED;
|
|
} else {
|
|
/* A standard toplevel window with borders and such. */
|
|
flStyle = FCF_STANDARD | WS_CLIPCHILDREN;
|
|
// flStyle = WS_OVERLAPPEDWINDOW;
|
|
}
|
|
}
|
|
{
|
|
HWND hwnd; /* Window */
|
|
ULONG ListBoxId; /* Window id */
|
|
/* (supplied by application) */
|
|
|
|
|
|
HWND hwndClient; /* handle to the client */
|
|
HWND hwndFrame; /* handle to the frame */
|
|
PFNWP GenericWndProc;
|
|
FRAMECDATA fcd;
|
|
RECTL rect; /* Boundary rectangle */
|
|
|
|
|
|
|
|
/************************************************/
|
|
// flCreate = (FCF_STANDARD) & ~FCF_TASKLIST;
|
|
/**********************************/
|
|
if (parent)
|
|
{ window->frame = NULL;
|
|
|
|
hwnd = WinCreateWindow(parent->win, /* Parent window */
|
|
"GLUTCHILD", /* Class name */
|
|
"", /* Window text */
|
|
flStyle, /* Window style */
|
|
x, y, /* Position (x,y) */
|
|
width, height, /* Size (width,height) */
|
|
parent->win, /* Owner window */
|
|
HWND_TOP, /* Sibling window */
|
|
0, /* Window id */
|
|
NULL, /* Control data */
|
|
NULL); /* Pres parameters */
|
|
|
|
erridErrorCode = WinGetLastError(hab);
|
|
window->win = hwnd;
|
|
|
|
window->hdc = WinOpenWindowDC(window->win);
|
|
window->hpsBuffer = hpsCurrent;
|
|
|
|
|
|
rect.xLeft = x;
|
|
rect.xRight = x+width;
|
|
rect.yBottom = y;
|
|
rect.yTop = y + height;
|
|
|
|
/***** else parent *****************************/
|
|
} else {
|
|
hwnd = WinCreateStdWindow(HWND_DESKTOP,
|
|
0, /* WS_VISIBLE frame-window style */
|
|
&flStyle, /* window style */
|
|
"GLUT", /* class name */
|
|
"GLUT",/* window title */
|
|
0L, /* default client style */
|
|
NULLHANDLE, /* resource in executable file */
|
|
ID_WINDOW, /* resource id */
|
|
&hwndClient); /* receives client window handle */
|
|
|
|
erridErrorCode = WinGetLastError(hab);
|
|
window->win = hwndClient;
|
|
window->frame = hwnd;
|
|
window->hdc = WinOpenWindowDC(window->win);
|
|
|
|
window->hpsBuffer = hpsCurrent;
|
|
|
|
|
|
/* converts a client window's boundaries into an equivalent frame rectangle */
|
|
rect.xLeft = x;
|
|
rect.xRight = x+width;
|
|
rect.yBottom = y;
|
|
rect.yTop = y + height;
|
|
|
|
/* calculate equivalent frame boundary from boundary data */
|
|
WinCalcFrameRect(window->frame, &rect, FALSE);
|
|
}
|
|
/***** endof if(parent) *****************************/
|
|
|
|
/* Must set the XHDC for fake glXChooseVisual & fake
|
|
glXCreateContext & fake XAllocColorCells. */
|
|
XHDC = window->hdc;
|
|
XHWND = window->win;
|
|
window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
|
|
&window->visAlloced, &fbc);
|
|
if (!window->vis)
|
|
{ __glutFatalError(
|
|
"pixel format with necessary capabilities not found.");
|
|
}
|
|
{ int rc;
|
|
rc = wglChoosePixelFormat(window->hdc, window->vis),
|
|
|
|
// evglSetPixelFormat(2); /* int iPixelFormat 1 - doublebuffer/2 - single buffer ??*/
|
|
wglSetPixelFormat(window->hdc,rc,window->vis);
|
|
}
|
|
__glutSetupColormap(window->vis, &window->colormap, &window->cmap);
|
|
|
|
window->ctx = glXCreateContext(window->hpsBuffer, window->vis,
|
|
None, __glutTryDirect);
|
|
|
|
WinSetWindowPos(hwnd,
|
|
HWND_TOP,rect.xLeft,rect.yBottom,
|
|
rect.xRight-rect.xLeft, rect.yTop-rect.yBottom,
|
|
SWP_ACTIVATE | SWP_MOVE | SWP_SIZE | SWP_SHOW|SWP_ZORDER); /* flags*/
|
|
|
|
/* Make sure subwindows get a windowStatus callback. */
|
|
if (parent)
|
|
WinPostMsg(parent->win, WM_ACTIVATE, 0, 0);
|
|
|
|
}
|
|
}
|
|
|
|
#elif defined(_WIN32)
|
|
|
|
__glutAdjustCoords(parent ? parent->win : NULL,
|
|
&x, &y, &width, &height);
|
|
if (parent) {
|
|
style = WS_CHILD;
|
|
} else {
|
|
if (gameMode) {
|
|
/* Game mode window should be a WS_POPUP window to
|
|
ensure that the taskbar is hidden by it. A standard
|
|
WS_OVERLAPPEDWINDOW does not hide the task bar. */
|
|
style = WS_POPUP | WS_MAXIMIZE;
|
|
} else {
|
|
/* A standard toplevel window with borders and such. */
|
|
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);
|
|
/* Must set the XHDC for fake glXChooseVisual & fake
|
|
glXCreateContext & fake XAllocColorCells. */
|
|
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);
|
|
/* Make sure subwindows get a windowStatus callback. */
|
|
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
|
|
#if defined(__OS2PM__)
|
|
// window->ctx = glXCreateContext(window->hpsBuffer, window->vis,
|
|
// None, __glutTryDirect);
|
|
#else
|
|
window->ctx = glXCreateContext(__glutDisplay, window->vis,
|
|
None, __glutTryDirect);
|
|
#endif
|
|
if (!window->ctx) {
|
|
__glutFatalError(
|
|
"failed to create OpenGL rendering context.");
|
|
}
|
|
window->renderCtx = window->ctx;
|
|
#if !defined(_WIN32) && !defined(__OS2PM__)
|
|
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
|
|
|
|
#if defined(__OS2PM__)
|
|
window->wm_command = NULL;
|
|
#endif
|
|
|
|
window->tabletPos[0] = -1;
|
|
window->tabletPos[1] = -1;
|
|
#if defined(__OS2PM__)
|
|
if(window->shownState == -1)
|
|
window->shownState = 0;
|
|
window->visState = window->shownState;
|
|
#else
|
|
window->shownState = 0;
|
|
window->visState = -1; /* not VisibilityUnobscured,
|
|
VisibilityPartiallyObscured, or
|
|
VisibilityFullyObscured */
|
|
#endif
|
|
window->entryState = -1; /* not EnterNotify or LeaveNotify */
|
|
|
|
window->desiredConfMask = 0;
|
|
window->buttonUses = 0;
|
|
window->cursor = GLUT_CURSOR_INHERIT;
|
|
|
|
/* Setup window to be mapped when glutMainLoop starts. */
|
|
window->workMask = GLUT_MAP_WORK;
|
|
#ifdef _WIN32
|
|
if (gameMode) {
|
|
/* When mapping a game mode window, just show
|
|
the window. We have already created the game
|
|
mode window with a maximize flag at creation
|
|
time. Doing a ShowWindow(window->win, SW_SHOWNORMAL)
|
|
would be wrong for a game mode window since it
|
|
would unmaximize the window. */
|
|
window->desiredMapState = GameModeState;
|
|
} else {
|
|
window->desiredMapState = NormalState;
|
|
}
|
|
#else
|
|
window->desiredMapState = NormalState;
|
|
#endif
|
|
window->prevWorkWin = __glutWindowWorkList;
|
|
__glutWindowWorkList = window;
|
|
|
|
/* Initially, no menus attached. */
|
|
for (i = 0; i < GLUT_MAX_MENUS; i++) {
|
|
window->menu[i] = 0;
|
|
}
|
|
|
|
/* Add this new window to the window list. */
|
|
__glutWindowList[winnum] = window;
|
|
|
|
/* Make the new window the current window. */
|
|
__glutSetWindow(window);
|
|
|
|
__glutDetermineMesaSwapHackSupport();
|
|
|
|
if (window->treatAsSingle) {
|
|
/* We do this because either the window really is single
|
|
buffered (in which case this is redundant, but harmless,
|
|
because this is the initial single-buffered context
|
|
state); or we are treating a double buffered window as a
|
|
single-buffered window because the system does not appear
|
|
to export any suitable single- buffered visuals (in which
|
|
the following are necessary). */
|
|
glDrawBuffer(GL_FRONT);
|
|
glReadBuffer(GL_FRONT);
|
|
}
|
|
return window;
|
|
}
|
|
|
|
/* CENTRY */
|
|
int GLUTAPIENTRY
|
|
glutCreateWindow(const char *title)
|
|
{
|
|
static int firstWindow = 1;
|
|
GLUTwindow *window;
|
|
#if !defined(_WIN32) && !defined(__OS2__)
|
|
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,
|
|
/* not game mode */ 0);
|
|
win = window->win;
|
|
/* Setup ICCCM properties. */
|
|
textprop.value = (unsigned char *) title;
|
|
textprop.encoding = XA_STRING;
|
|
textprop.format = 8;
|
|
textprop.nitems = strlen(title);
|
|
#if defined(__OS2__)
|
|
WinSetWindowText(window->frame, (PCSZ)title);
|
|
if (__glutIconic) {
|
|
window->desiredMapState = IconicState;
|
|
}
|
|
#elif 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,
|
|
/* Only put WM_COMMAND property on first window. */
|
|
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, /* not game mode */ 0);
|
|
#if !defined(_WIN32) && !defined(__OS2__)
|
|
{
|
|
GLUTwindow *toplevel;
|
|
|
|
toplevel = __glutToplevelOf(window);
|
|
if (toplevel->cmap != window->cmap) {
|
|
__glutPutOnWorkList(toplevel, GLUT_COLORMAP_WORK);
|
|
}
|
|
}
|
|
#endif
|
|
return window->num + 1;
|
|
}
|
|
/* ENDCENTRY */
|
|
|
|
void
|
|
__glutDestroyWindow(GLUTwindow * window,
|
|
GLUTwindow * initialWindow)
|
|
{
|
|
GLUTwindow **prev, *cur, *parent, *siblings;
|
|
|
|
/* Recursively destroy any children. */
|
|
cur = window->children;
|
|
while (cur) {
|
|
siblings = cur->siblings;
|
|
__glutDestroyWindow(cur, initialWindow);
|
|
cur = siblings;
|
|
}
|
|
/* Remove from parent's children list (only necessary for
|
|
non-initial windows and subwindows!). */
|
|
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;
|
|
}
|
|
}
|
|
/* Unbind if bound to this window. */
|
|
if (window == __glutCurrentWindow) {
|
|
UNMAKE_CURRENT();
|
|
__glutCurrentWindow = NULL;
|
|
}
|
|
/* Begin tearing down window itself. */
|
|
if (window->overlay) {
|
|
__glutFreeOverlayFunc(window->overlay);
|
|
}
|
|
XDestroyWindow(__glutDisplay, window->win);
|
|
glXDestroyContext(__glutDisplay, window->ctx);
|
|
if (window->colormap) {
|
|
/* Only color index windows have colormap data structure. */
|
|
__glutFreeColormap(window->colormap);
|
|
}
|
|
/* NULLing the __glutWindowList helps detect is a window
|
|
instance has been destroyed, given a window number. */
|
|
__glutWindowList[window->num] = NULL;
|
|
|
|
/* Cleanup data structures that might contain window. */
|
|
cleanWindowWorkList(window);
|
|
#if !defined(_WIN32) && !defined(__OS2__)
|
|
cleanStaleWindowList(window);
|
|
#endif
|
|
/* Remove window from the "get window cache" if it is there. */
|
|
if (__glutWindowCache == window)
|
|
__glutWindowCache = NULL;
|
|
|
|
if (window->visAlloced) {
|
|
/* Only free XVisualInfo* gotten from glXChooseVisual. */
|
|
XFree(window->vis);
|
|
}
|
|
|
|
if (window == __glutGameModeWindow) {
|
|
/* Destroying the game mode window should implicitly
|
|
have GLUT leave game mode. */
|
|
__glutCloseDownGameMode();
|
|
}
|
|
|
|
free(window);
|
|
}
|
|
|
|
/* CENTRY */
|
|
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) && !defined(__OS2__)
|
|
/* If not a toplevel window... */
|
|
if (window->parent) {
|
|
/* Destroying subwindows may change colormap requirements;
|
|
recalculate toplevel window's WM_COLORMAP_WINDOWS
|
|
property. */
|
|
__glutPutOnWorkList(__glutToplevelOf(window->parent),
|
|
GLUT_COLORMAP_WORK);
|
|
}
|
|
#endif
|
|
__glutDestroyWindow(window, window);
|
|
XFlush(__glutDisplay);
|
|
}
|
|
/* ENDCENTRY */
|
|
|
|
void
|
|
__glutChangeWindowEventMask(long eventMask, Bool add)
|
|
{
|
|
if (add) {
|
|
/* Add eventMask to window's event mask. */
|
|
if ((__glutCurrentWindow->eventMask & eventMask) !=
|
|
eventMask) {
|
|
__glutCurrentWindow->eventMask |= eventMask;
|
|
__glutPutOnWorkList(__glutCurrentWindow,
|
|
GLUT_EVENT_MASK_WORK);
|
|
}
|
|
} else {
|
|
/* Remove eventMask from window's event mask. */
|
|
if (__glutCurrentWindow->eventMask & eventMask) {
|
|
__glutCurrentWindow->eventMask &= ~eventMask;
|
|
__glutPutOnWorkList(__glutCurrentWindow,
|
|
GLUT_EVENT_MASK_WORK);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GLUTAPIENTRY
|
|
glutDisplayFunc(GLUTdisplayCB displayFunc)
|
|
{
|
|
/* XXX Remove the warning after GLUT 3.0. */
|
|
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) {
|
|
/* Previous mouseFunc being disabled. */
|
|
__glutCurrentWindow->buttonUses--;
|
|
__glutChangeWindowEventMask(
|
|
ButtonPressMask | ButtonReleaseMask,
|
|
__glutCurrentWindow->buttonUses > 0);
|
|
}
|
|
} else {
|
|
if (mouseFunc) {
|
|
/* Previously no mouseFunc, new one being installed. */
|
|
__glutCurrentWindow->buttonUses++;
|
|
__glutChangeWindowEventMask(
|
|
ButtonPressMask | ButtonReleaseMask, True);
|
|
}
|
|
}
|
|
__glutCurrentWindow->mouse = mouseFunc;
|
|
}
|
|
|
|
void GLUTAPIENTRY
|
|
glutMotionFunc(GLUTmotionCB motionFunc)
|
|
{
|
|
/* Hack. Some window managers (4Dwm by default) will mask
|
|
motion events if the client is not selecting for button
|
|
press and release events. So we select for press and
|
|
release events too (being careful to use reference
|
|
counting). */
|
|
if (__glutCurrentWindow->motion) {
|
|
if (!motionFunc) {
|
|
/* previous mouseFunc being disabled */
|
|
__glutCurrentWindow->buttonUses--;
|
|
__glutChangeWindowEventMask(
|
|
ButtonPressMask | ButtonReleaseMask,
|
|
__glutCurrentWindow->buttonUses > 0);
|
|
}
|
|
} else {
|
|
if (motionFunc) {
|
|
/* Previously no mouseFunc, new one being installed. */
|
|
__glutCurrentWindow->buttonUses++;
|
|
__glutChangeWindowEventMask(
|
|
ButtonPressMask | ButtonReleaseMask, True);
|
|
}
|
|
}
|
|
/* Real work of selecting for passive mouse motion. */
|
|
__glutChangeWindowEventMask(
|
|
Button1MotionMask | Button2MotionMask | Button3MotionMask,
|
|
motionFunc != NULL);
|
|
__glutCurrentWindow->motion = motionFunc;
|
|
}
|
|
|
|
void GLUTAPIENTRY
|
|
glutPassiveMotionFunc(GLUTpassiveCB passiveMotionFunc)
|
|
{
|
|
__glutChangeWindowEventMask(PointerMotionMask,
|
|
passiveMotionFunc != NULL);
|
|
|
|
/* Passive motion also requires watching enters and leaves so
|
|
that a fake passive motion event can be generated on an
|
|
enter. */
|
|
__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) {
|
|
/* Make state invalid. */
|
|
__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);
|
|
#if defined(__OS2PM__)
|
|
if(__glutCurrentWindow->shownState >= 0)
|
|
{ visibilityHelper(__glutCurrentWindow->shownState);
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
glutWindowStatusFunc(NULL);
|
|
}
|
|
|
|
void GLUTAPIENTRY
|
|
glutReshapeFunc(GLUTreshapeCB reshapeFunc)
|
|
{
|
|
if (reshapeFunc) {
|
|
__glutCurrentWindow->reshape = reshapeFunc;
|
|
} else {
|
|
__glutCurrentWindow->reshape = __glutDefaultReshape;
|
|
}
|
|
}
|