X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ffreeglut_window.c;h=c7a07c6ab084cbb1eef7514df31354ea7902e80c;hb=a1ff6aa662af045fc32c9241ef48a6ff019e0018;hp=60a72f156a070e57a1462b294ca7c3e306f29db8;hpb=909ac32d797d79a6e747ed4abc2492d562a4dd46;p=freeglut diff --git a/src/freeglut_window.c b/src/freeglut_window.c index 60a72f1..c7a07c6 100644 --- a/src/freeglut_window.c +++ b/src/freeglut_window.c @@ -25,17 +25,130 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifdef HAVE_CONFIG_H -#include "config.h" +#define FREEGLUT_BUILDING_LIB +#include +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 +#include /* LONG_MAX */ #endif -#include "../include/GL/freeglut.h" -#include "freeglut_internal.h" +#if defined(_WIN32_WCE) +# include +# ifdef FREEGLUT_LIB_PRAGMAS +# pragma comment( lib, "Aygshell.lib" ) +# endif +#endif /* defined(_WIN32_WCE) */ + + +#if TARGET_HOST_POSIX_X11 +#ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 +#endif + +#ifndef GLX_CONTEXT_MAJOR_VERSION_ARB +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#endif + +#ifndef GLX_CONTEXT_MINOR_VERSION_ARB +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#endif + +#ifndef GLX_CONTEXT_FLAGS_ARB +#define GLX_CONTEXT_FLAGS_ARB 0x2094 +#endif + +#ifndef GLX_CONTEXT_PROFILE_MASK_ARB +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#endif + +#ifndef GLX_CONTEXT_DEBUG_BIT_ARB +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 +#endif + +#ifndef GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#endif + +#ifndef GLX_CONTEXT_CORE_PROFILE_BIT_ARB +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#endif + +#ifndef GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#endif + +#ifndef GLX_RGBA_FLOAT_TYPE +#define GLX_RGBA_FLOAT_TYPE 0x20B9 +#endif + +#ifndef GLX_RGBA_FLOAT_BIT +#define GLX_RGBA_FLOAT_BIT 0x00000004 +#endif +#endif /* TARGET_HOST_POSIX_X11 */ + + +#if TARGET_HOST_MS_WINDOWS +/* The following include file is available from SGI but is not standard: + * #include + * So we copy the necessary parts out of it. + * XXX: should local definitions for extensions be put in a separate include file? + */ +typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); + +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); + +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_FULL_ACCELERATION_ARB 0x2027 + +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 + +#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 + +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 + +#ifndef WGL_ARB_create_context +#define WGL_ARB_create_context 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); + +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 + +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 + +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 + +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#endif + +#endif /* TARGET_HOST_MS_WINDOWS */ + + +/* pushing attribute/value pairs into an array */ +#define ATTRIB(a) attributes[where++]=(a) +#define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);} /* * TODO BEFORE THE STABLE RELEASE: * - * fgChooseVisual() -- OK, but what about glutInitDisplayString()? + * fgChooseFBConfig() -- OK, but what about glutInitDisplayString()? * fgSetupPixelFormat -- ignores the display mode settings * fgOpenWindow() -- check the Win32 version, -iconic handling! * fgCloseWindow() -- check the Win32 version @@ -57,192 +170,740 @@ /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ -/* - * Chooses a visual basing on the current display mode settings - */ -#if TARGET_HOST_UNIX_X11 +static int fghIsLegacyContextVersionRequested( void ) +{ + return fgState.MajorVersion == 1 && fgState.MinorVersion == 0; +} -XVisualInfo* fgChooseVisual( void ) +static int fghIsLegacyContextRequested( void ) { -#define BUFFER_SIZES 6 - int bufferSize[BUFFER_SIZES] = { 16, 12, 8, 4, 2, 1 }; - GLboolean wantIndexedMode = GL_FALSE; - int attributes[ 32 ]; - int where = 0; + return fghIsLegacyContextVersionRequested() && + fgState.ContextFlags == 0 && + fgState.ContextProfile == 0; +} - /* - * First we have to process the display mode settings... - */ +static int fghNumberOfAuxBuffersRequested( void ) +{ + if ( fgState.DisplayMode & GLUT_AUX4 ) { + return 4; + } + if ( fgState.DisplayMode & GLUT_AUX3 ) { + return 3; + } + if ( fgState.DisplayMode & GLUT_AUX2 ) { + return 2; + } + if ( fgState.DisplayMode & GLUT_AUX1 ) { /* NOTE: Same as GLUT_AUX! */ + return fgState.AuxiliaryBufferNumber; + } + return 0; +} + +static int fghMapBit( int mask, int from, int to ) +{ + return ( mask & from ) ? to : 0; + +} + +static void fghContextCreationError( void ) +{ + fgError( "Unable to create OpenGL %d.%d context (flags %x, profile %x)", + fgState.MajorVersion, fgState.MinorVersion, fgState.ContextFlags, + fgState.ContextProfile ); +} + + +/* -- SYSTEM-DEPENDENT PRIVATE FUNCTIONS ------------------------------------ */ + +#if TARGET_HOST_POSIX_X11 /* - * Why is there a semi-colon in this #define? The code - * that uses the macro seems to always add more semicolons... + * Chooses a visual basing on the current display mode settings */ -#define ATTRIB(a) attributes[where++]=a; -#define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);} - if( fgState.DisplayMode & GLUT_INDEX ) - { - ATTRIB_VAL( GLX_BUFFER_SIZE, 8 ); - wantIndexedMode = GL_TRUE; +GLXFBConfig* fgChooseFBConfig( int *numcfgs ) +{ + GLboolean wantIndexedMode = GL_FALSE; + int attributes[ 100 ]; + int where = 0, numAuxBuffers; + + /* First we have to process the display mode settings... */ + if( fgState.DisplayMode & GLUT_INDEX ) { + ATTRIB_VAL( GLX_BUFFER_SIZE, 8 ); + /* Buffer size is selected later. */ + + ATTRIB_VAL( GLX_RENDER_TYPE, GLX_COLOR_INDEX_BIT ); + wantIndexedMode = GL_TRUE; + } else { + ATTRIB_VAL( GLX_RED_SIZE, 1 ); + ATTRIB_VAL( GLX_GREEN_SIZE, 1 ); + ATTRIB_VAL( GLX_BLUE_SIZE, 1 ); + if( fgState.DisplayMode & GLUT_ALPHA ) { + ATTRIB_VAL( GLX_ALPHA_SIZE, 1 ); } - else - { - ATTRIB( GLX_RGBA ); - ATTRIB_VAL( GLX_RED_SIZE, 1 ); - ATTRIB_VAL( GLX_GREEN_SIZE, 1 ); - ATTRIB_VAL( GLX_BLUE_SIZE, 1 ); - if( fgState.DisplayMode & GLUT_ALPHA ) - ATTRIB_VAL( GLX_ALPHA_SIZE, 1 ); + } + + if( fgState.DisplayMode & GLUT_DOUBLE ) { + ATTRIB_VAL( GLX_DOUBLEBUFFER, True ); + } + + if( fgState.DisplayMode & GLUT_STEREO ) { + ATTRIB_VAL( GLX_STEREO, True ); + } + + if( fgState.DisplayMode & GLUT_DEPTH ) { + ATTRIB_VAL( GLX_DEPTH_SIZE, 1 ); + } + + if( fgState.DisplayMode & GLUT_STENCIL ) { + ATTRIB_VAL( GLX_STENCIL_SIZE, 1 ); + } + + if( fgState.DisplayMode & GLUT_ACCUM ) { + ATTRIB_VAL( GLX_ACCUM_RED_SIZE, 1 ); + ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 ); + ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE, 1 ); + if( fgState.DisplayMode & GLUT_ALPHA ) { + ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 ); } + } - if( fgState.DisplayMode & GLUT_DOUBLE ) - ATTRIB( GLX_DOUBLEBUFFER ); + numAuxBuffers = fghNumberOfAuxBuffersRequested(); + if ( numAuxBuffers > 0 ) { + ATTRIB_VAL( GLX_AUX_BUFFERS, numAuxBuffers ); + } - if( fgState.DisplayMode & GLUT_STEREO ) - ATTRIB( GLX_STEREO ); + if( fgState.DisplayMode & GLUT_SRGB ) { + ATTRIB_VAL( GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True ); + } - if( fgState.DisplayMode & GLUT_DEPTH ) - ATTRIB_VAL( GLX_DEPTH_SIZE, 1 ); + if (fgState.DisplayMode & GLUT_MULTISAMPLE) { + ATTRIB_VAL(GLX_SAMPLE_BUFFERS, 1); + ATTRIB_VAL(GLX_SAMPLES, fgState.SampleNumber); + } - if( fgState.DisplayMode & GLUT_STENCIL ) - ATTRIB_VAL( GLX_STENCIL_SIZE, 1 ); + /* Push a terminator at the end of the list */ + ATTRIB( None ); - if( fgState.DisplayMode & GLUT_ACCUM ) { - ATTRIB_VAL( GLX_ACCUM_RED_SIZE, 1 ); - ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 ); - ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE, 1 ); - if( fgState.DisplayMode & GLUT_ALPHA ) - ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 ); + GLXFBConfig * fbconfigArray; /* Array of FBConfigs */ + GLXFBConfig * fbconfig; /* The FBConfig we want */ + int fbconfigArraySize; /* Number of FBConfigs in the array */ + + + /* Get all FBConfigs that match "attributes". */ + fbconfigArray = glXChooseFBConfig( fgDisplay.Display, + fgDisplay.Screen, + attributes, + &fbconfigArraySize ); + + if (fbconfigArray != NULL) + { + int result; /* Returned by glXGetFBConfigAttrib, not checked. */ + + + if( wantIndexedMode ) + { + /* + * In index mode, we want the largest buffer size, i.e. visual + * depth. Here, FBConfigs are sorted by increasing buffer size + * first, so FBConfigs with the largest size come last. + */ + + int bufferSizeMin, bufferSizeMax; + + /* Get bufferSizeMin. */ + result = + glXGetFBConfigAttrib( fgDisplay.Display, + fbconfigArray[0], + GLX_BUFFER_SIZE, + &bufferSizeMin ); + /* Get bufferSizeMax. */ + result = + glXGetFBConfigAttrib( fgDisplay.Display, + fbconfigArray[fbconfigArraySize - 1], + GLX_BUFFER_SIZE, + &bufferSizeMax ); + + if (bufferSizeMax > bufferSizeMin) + { + /* + * Free and reallocate fbconfigArray, keeping only FBConfigs + * with the largest buffer size. + */ + XFree(fbconfigArray); + + /* Add buffer size token at the end of the list. */ + where--; + ATTRIB_VAL( GLX_BUFFER_SIZE, bufferSizeMax ); + ATTRIB( None ); + + fbconfigArray = glXChooseFBConfig( fgDisplay.Display, + fgDisplay.Screen, + attributes, + &fbconfigArraySize ); + } + } + + /* + * We now have an array of FBConfigs, the first one being the "best" + * one. So we should return only this FBConfig: + * + * int fbconfigXID; + * + * - pick the XID of the FBConfig we want + * result = glXGetFBConfigAttrib( fgDisplay.Display, + * fbconfigArray[0], + * GLX_FBCONFIG_ID, + * &fbconfigXID ); + * + * - free the array + * XFree(fbconfigArray); + * + * - reset "attributes" with the XID + * where = 0; + * ATTRIB_VAL( GLX_FBCONFIG_ID, fbconfigXID ); + * ATTRIB( None ); + * + * - get our FBConfig only + * fbconfig = glXChooseFBConfig( fgDisplay.Display, + * fgDisplay.Screen, + * attributes, + * &fbconfigArraySize ); + * + * However, for some configurations (for instance multisampling with + * Mesa 6.5.2 and ATI drivers), this does not work: + * glXChooseFBConfig returns NULL, whereas fbconfigXID is a valid + * XID. Further investigation is needed. + * + * So, for now, we return the whole array of FBConfigs. This should + * not produce any side effects elsewhere. + */ + fbconfig = fbconfigArray; + } + else + { + fbconfig = NULL; + } + + if (numcfgs) + *numcfgs = fbconfigArraySize; + + return fbconfig; } +} - /* - * Push a null at the end of the list - */ - ATTRIB( None ); - if( ! wantIndexedMode ) - return glXChooseVisual( fgDisplay.Display, fgDisplay.Screen, - attributes ); - else - { - XVisualInfo* visualInfo; - int i; +static void fghFillContextAttributes( int *attributes ) { + int where = 0, contextFlags, contextProfile; + + if ( !fghIsLegacyContextVersionRequested() ) { + ATTRIB_VAL( GLX_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion ); + ATTRIB_VAL( GLX_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion ); + } + + contextFlags = + fghMapBit( fgState.ContextFlags, GLUT_DEBUG, GLX_CONTEXT_DEBUG_BIT_ARB ) | + fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB ); + if ( contextFlags != 0 ) { + ATTRIB_VAL( GLX_CONTEXT_FLAGS_ARB, contextFlags ); + } + + contextProfile = + fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB ) | + fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ); + if ( contextProfile != 0 ) { + ATTRIB_VAL( GLX_CONTEXT_PROFILE_MASK_ARB, contextProfile ); + } + + ATTRIB( 0 ); +} + +typedef GLXContext (*CreateContextAttribsProc)(Display *dpy, GLXFBConfig config, + GLXContext share_list, Bool direct, + const int *attrib_list); + +static GLXContext fghCreateNewContext( SFG_Window* window ) +{ + /* for color model calculation */ + int menu = ( window->IsMenu && !fgStructure.MenuContext ); + int index_mode = ( fgState.DisplayMode & GLUT_INDEX ); + + /* "classic" context creation */ + Display *dpy = fgDisplay.Display; + GLXFBConfig config = *(window->Window.FBConfig); + int render_type = ( !menu && index_mode ) ? GLX_COLOR_INDEX_TYPE : GLX_RGBA_TYPE; + GLXContext share_list = NULL; + Bool direct = ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT ); + GLXContext context; + + /* new context creation */ + int attributes[9]; + CreateContextAttribsProc createContextAttribs; + + /* If nothing fancy has been required, simply use the old context creation GLX API entry */ + if ( fghIsLegacyContextRequested() ) + { + context = glXCreateNewContext( dpy, config, render_type, share_list, direct ); + if ( context == NULL ) { + fghContextCreationError(); + } + return context; + } + + /* color index mode is not available anymore with OpenGL 3.0 */ + if ( render_type == GLX_COLOR_INDEX_TYPE ) { + fgWarning( "color index mode is deprecated, using RGBA mode" ); + } + + fghFillContextAttributes( attributes ); + + createContextAttribs = (CreateContextAttribsProc) fghGetProcAddress( "glXCreateContextAttribsARB" ); + if ( createContextAttribs == NULL ) { + fgError( "glXCreateContextAttribsARB not found" ); + } + + context = createContextAttribs( dpy, config, share_list, direct, attributes ); + if ( context == NULL ) { + fghContextCreationError(); + } + return context; +} + +#define _NET_WM_STATE_TOGGLE 2 +static int fghResizeFullscrToggle(void) +{ + XWindowAttributes attributes; + + if(glutGet(GLUT_FULL_SCREEN)) { + /* restore original window size */ + SFG_Window *win = fgStructure.CurrentWindow; + fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; + fgStructure.CurrentWindow->State.Width = win->State.OldWidth; + fgStructure.CurrentWindow->State.Height = win->State.OldHeight; + + } else { + /* resize the window to cover the entire screen */ + XGetWindowAttributes(fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &attributes); + /* - * In indexed mode, we need to check how many bits of depth can we - * achieve. We do this by trying each possibility from the list - * given in the {bufferSize} array. If we match, we return to caller. + * The "x" and "y" members of "attributes" are the window's coordinates + * relative to its parent, i.e. to the decoration window. */ - for( i=0; iWindow.Handle, + -attributes.x, + -attributes.y, + fgDisplay.ScreenWidth, + fgDisplay.ScreenHeight); } + return 0; +} + +static int fghEwmhFullscrToggle(void) +{ + XEvent xev; + long evmask = SubstructureRedirectMask | SubstructureNotifyMask; + + if(!fgDisplay.State || !fgDisplay.StateFullScreen) { + return -1; + } + + xev.type = ClientMessage; + xev.xclient.window = fgStructure.CurrentWindow->Window.Handle; + xev.xclient.message_type = fgDisplay.State; + xev.xclient.format = 32; + xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE; + xev.xclient.data.l[1] = fgDisplay.StateFullScreen; + xev.xclient.data.l[2] = 0; /* no second property to toggle */ + xev.xclient.data.l[3] = 1; /* source indication: application */ + xev.xclient.data.l[4] = 0; /* unused */ + + if(!XSendEvent(fgDisplay.Display, fgDisplay.RootWindow, 0, evmask, &xev)) { + return -1; + } + return 0; +} + +static int fghToggleFullscreen(void) +{ + /* first try the EWMH (_NET_WM_STATE) method ... */ + if(fghEwmhFullscrToggle() != -1) { + return 0; + } + + /* fall back to resizing the window */ + if(fghResizeFullscrToggle() != -1) { + return 0; + } + return -1; } -#endif + +#endif /* TARGET_HOST_POSIX_X11 */ + + +#if TARGET_HOST_MS_WINDOWS /* * Setup the pixel format for a Win32 window */ -#if TARGET_HOST_WIN32 -GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, - unsigned char layer_type ) + +#if defined(_WIN32_WCE) +static wchar_t* fghWstrFromStr(const char* str) { - PIXELFORMATDESCRIPTOR* ppfd, pfd; - int flags, pixelformat; + int i,len=strlen(str); + wchar_t* wstr = (wchar_t*)malloc(2*len+2); + for(i=0; iWindow.Device, window->Window.Context ); + + if ( !fghIsExtensionSupported( window->Window.Device, "WGL_ARB_create_context" ) ) + { + return; + } + + /* new context creation */ + fghFillContextAttributes( attributes ); + + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress( "wglCreateContextAttribsARB" ); + if ( wglCreateContextAttribsARB == NULL ) + { + fgError( "wglCreateContextAttribsARB not found" ); + } + + context = wglCreateContextAttribsARB( window->Window.Device, 0, attributes ); + if ( context == NULL ) + { + fghContextCreationError(); + } + + wglMakeCurrent( NULL, NULL ); + wglDeleteContext( window->Window.Context ); + window->Window.Context = context; +} + +#if !defined(_WIN32_WCE) - freeglut_return_val_if_fail( window != NULL, 0 ); - flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; - if( fgState.DisplayMode & GLUT_DOUBLE ) +static void fghFillPFD( PIXELFORMATDESCRIPTOR *ppfd, HDC hdc, unsigned char layer_type ) +{ + int flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; + if ( fgState.DisplayMode & GLUT_DOUBLE ) { flags |= PFD_DOUBLEBUFFER; + } + if ( fgState.DisplayMode & GLUT_STEREO ) { + flags |= PFD_STEREO; + } #if defined(_MSC_VER) #pragma message( "fgSetupPixelFormat(): there is still some work to do here!" ) #endif - /* - * Specify which pixel format do we opt for... - */ - pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); - pfd.nVersion = 1; - pfd.dwFlags = flags; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 24; - pfd.cRedBits = 0; - pfd.cRedShift = 0; - pfd.cGreenBits = 0; - pfd.cGreenShift = 0; - pfd.cBlueBits = 0; - pfd.cBlueShift = 0; - pfd.cAlphaBits = 0; - pfd.cAlphaShift = 0; - pfd.cAccumBits = 0; - pfd.cAccumRedBits = 0; - pfd.cAccumGreenBits = 0; - pfd.cAccumBlueBits = 0; - pfd.cAccumAlphaBits = 0; -#if 0 - pfd.cDepthBits = 32; - pfd.cStencilBits = 0; -#else - pfd.cDepthBits = 24; - pfd.cStencilBits = 8; -#endif - pfd.cAuxBuffers = 0; - pfd.iLayerType = layer_type; - pfd.bReserved = 0; - pfd.dwLayerMask = 0; - pfd.dwVisibleMask = 0; - pfd.dwDamageMask = 0; - - pfd.cColorBits = (BYTE) GetDeviceCaps( window->Window.Device, BITSPIXEL ); - ppfd = &pfd; - - pixelformat = ChoosePixelFormat( window->Window.Device, ppfd ); - if( pixelformat == 0 ) - return GL_FALSE; - - if( checkOnly ) - return GL_TRUE; - return SetPixelFormat( window->Window.Device, pixelformat, ppfd ); + /* Specify which pixel format do we opt for... */ + ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); + ppfd->nVersion = 1; + ppfd->dwFlags = flags; + + if( fgState.DisplayMode & GLUT_INDEX ) { + ppfd->iPixelType = PFD_TYPE_COLORINDEX; + ppfd->cRedBits = 0; + ppfd->cGreenBits = 0; + ppfd->cBlueBits = 0; + ppfd->cAlphaBits = 0; + } else { + ppfd->iPixelType = PFD_TYPE_RGBA; + ppfd->cRedBits = 8; + ppfd->cGreenBits = 8; + ppfd->cBlueBits = 8; + ppfd->cAlphaBits = ( fgState.DisplayMode & GLUT_ALPHA ) ? 8 : 0; + } + + ppfd->cColorBits = 24; + ppfd->cRedShift = 0; + ppfd->cGreenShift = 0; + ppfd->cBlueShift = 0; + ppfd->cAlphaShift = 0; + ppfd->cAccumBits = 0; + ppfd->cAccumRedBits = 0; + ppfd->cAccumGreenBits = 0; + ppfd->cAccumBlueBits = 0; + ppfd->cAccumAlphaBits = 0; + + /* Hmmm, or 32/0 instead of 24/8? */ + ppfd->cDepthBits = 24; + ppfd->cStencilBits = 8; + + ppfd->cAuxBuffers = fghNumberOfAuxBuffersRequested(); + ppfd->iLayerType = layer_type; + ppfd->bReserved = 0; + ppfd->dwLayerMask = 0; + ppfd->dwVisibleMask = 0; + ppfd->dwDamageMask = 0; + + ppfd->cColorBits = (BYTE) GetDeviceCaps( hdc, BITSPIXEL ); +} + +static void fghFillPixelFormatAttributes( int *attributes, const PIXELFORMATDESCRIPTOR *ppfd ) +{ + int where = 0; + + ATTRIB_VAL( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_SUPPORT_OPENGL_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB ); + + ATTRIB_VAL( WGL_COLOR_BITS_ARB, ppfd->cColorBits ); + ATTRIB_VAL( WGL_ALPHA_BITS_ARB, ppfd->cAlphaBits ); + ATTRIB_VAL( WGL_DEPTH_BITS_ARB, ppfd->cDepthBits ); + ATTRIB_VAL( WGL_STENCIL_BITS_ARB, ppfd->cStencilBits ); + + ATTRIB_VAL( WGL_DOUBLE_BUFFER_ARB, ( fgState.DisplayMode & GLUT_DOUBLE ) != 0 ); + + if ( fgState.DisplayMode & GLUT_SRGB ) { + ATTRIB_VAL( WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE ); + } + + ATTRIB_VAL( WGL_SAMPLE_BUFFERS_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_SAMPLES_ARB, fgState.SampleNumber ); + ATTRIB( 0 ); } #endif +GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, + unsigned char layer_type ) +{ +#if defined(_WIN32_WCE) + return GL_TRUE; +#else + PIXELFORMATDESCRIPTOR pfd; + PIXELFORMATDESCRIPTOR* ppfd = &pfd; + int pixelformat; + HDC current_hDC; + GLboolean success; + + if (checkOnly) + current_hDC = CreateDC(TEXT("DISPLAY"), NULL ,NULL ,NULL); + else + current_hDC = window->Window.Device; + + fghFillPFD( ppfd, current_hDC, layer_type ); + pixelformat = ChoosePixelFormat( current_hDC, ppfd ); + + /* windows hack for multismapling/sRGB */ + if ( ( fgState.DisplayMode & GLUT_MULTISAMPLE ) || + ( fgState.DisplayMode & GLUT_SRGB ) ) + { + HGLRC rc, rc_before=wglGetCurrentContext(); + HWND hWnd; + HDC hDC, hDC_before=wglGetCurrentDC(); + WNDCLASS wndCls; + + /* create a dummy window */ + ZeroMemory(&wndCls, sizeof(wndCls)); + wndCls.lpfnWndProc = DefWindowProc; + wndCls.hInstance = fgDisplay.Instance; + wndCls.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + wndCls.lpszClassName = _T("FREEGLUT_dummy"); + RegisterClass( &wndCls ); + + hWnd=CreateWindow(_T("FREEGLUT_dummy"), _T(""), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW , 0,0,0,0, 0, 0, fgDisplay.Instance, 0 ); + hDC=GetDC(hWnd); + SetPixelFormat( hDC, pixelformat, ppfd ); + + rc = wglCreateContext( hDC ); + wglMakeCurrent(hDC, rc); + + if ( fghIsExtensionSupported( hDC, "WGL_ARB_multisample" ) ) + { + PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARBProc = + (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB"); + if ( wglChoosePixelFormatARBProc ) + { + int attributes[100]; + int iPixelFormat; + BOOL bValid; + float fAttributes[] = { 0, 0 }; + UINT numFormats; + fghFillPixelFormatAttributes( attributes, ppfd ); + bValid = wglChoosePixelFormatARBProc(hDC, attributes, fAttributes, 1, &iPixelFormat, &numFormats); + + if ( bValid && numFormats > 0 ) + { + pixelformat = iPixelFormat; + } + } + } + + wglMakeCurrent( hDC_before, rc_before); + wglDeleteContext(rc); + ReleaseDC(hWnd, hDC); + DestroyWindow(hWnd); + UnregisterClass(_T("FREEGLUT_dummy"), fgDisplay.Instance); + } + + success = ( pixelformat != 0 ) && ( checkOnly || SetPixelFormat( current_hDC, pixelformat, ppfd ) ); + + if (checkOnly) + DeleteDC(current_hDC); + + return success; +#endif /* defined(_WIN32_WCE) */ +} + +#endif /* TARGET_HOST_MS_WINDOWS */ + /* * Sets the OpenGL context and the fgStructure "Current Window" pointer to * the window structure passed in. */ void fgSetWindow ( SFG_Window *window ) { -#if TARGET_HOST_UNIX_X11 +#if TARGET_HOST_POSIX_X11 if ( window ) - glXMakeCurrent( + { + glXMakeContextCurrent( fgDisplay.Display, window->Window.Handle, + window->Window.Handle, window->Window.Context ); -#elif TARGET_HOST_WIN32 - if( fgStructure.Window ) - ReleaseDC( fgStructure.Window->Window.Handle, - fgStructure.Window->Window.Device ); - - if ( window ) + } +#elif TARGET_HOST_MS_WINDOWS + if ( window != fgStructure.CurrentWindow ) { - window->Window.Device = GetDC( window->Window.Handle ); - wglMakeCurrent( - window->Window.Device, - window->Window.Context - ); + if( fgStructure.CurrentWindow ) + ReleaseDC( fgStructure.CurrentWindow->Window.Handle, + fgStructure.CurrentWindow->Window.Device ); + + if ( window ) + { + window->Window.Device = GetDC( window->Window.Handle ); + wglMakeCurrent( + window->Window.Device, + window->Window.Context + ); + } } #endif - fgStructure.Window = window; + fgStructure.CurrentWindow = window; +} + +#if TARGET_HOST_MS_WINDOWS + +#if(WINVER >= 0x500) +typedef struct { + int *x; + int *y; + const char *name; +}m_proc_t ; + +static BOOL CALLBACK m_proc(HMONITOR mon, + HDC hdc, + LPRECT rect, + LPARAM data) +{ + m_proc_t *dp=(m_proc_t *)data; + MONITORINFOEX info; + BOOL res; + info.cbSize=sizeof(info); + res=GetMonitorInfo(mon,(LPMONITORINFO)&info); + if( res ) + { + if( !strcmp(dp->name,info.szDevice) ) + { + *(dp->x)=info.rcMonitor.left; + *(dp->y)=info.rcMonitor.top; + return FALSE; + } + } + return TRUE; +} + +/* + * this function is only used in fgOpenWindow. Currently it only sets + * its output parameters, if the DisplayName is set in fgDisplay + * (and if it is able to recognize the display) + */ + +static void get_display_origin(int *xp,int *yp) +{ + if( fgDisplay.DisplayName ) + { + m_proc_t st; + st.x=xp; + st.y=yp; + st.name=fgDisplay.DisplayName; + EnumDisplayMonitors(0,0,m_proc,(LPARAM)&st); + } +} +#else +#pragma message( "-display parameter only works if compiled with WINVER >= 0x0500") + +static void get_display_origin(int *xp,int *yp) +{ + if( fgDisplay.DisplayName ) + { + fgWarning( "for working -display support FreeGLUT must be compiled with WINVER >= 0x0500"); + } } +#endif +#endif + /* @@ -250,132 +911,117 @@ void fgSetWindow ( SFG_Window *window ) * to the freeglut structure. OpenGL context is created here. */ void fgOpenWindow( SFG_Window* window, const char* title, - int x, int y, int w, int h, + GLboolean positionUse, int x, int y, + GLboolean sizeUse, int w, int h, GLboolean gameMode, GLboolean isSubWindow ) { -#if TARGET_HOST_UNIX_X11 +#if TARGET_HOST_POSIX_X11 + XVisualInfo * visualInfo; XSetWindowAttributes winAttr; XTextProperty textProperty; XSizeHints sizeHints; XWMHints wmHints; unsigned long mask; + int num_FBConfigs, i; + unsigned int current_DisplayMode = fgState.DisplayMode ; - freeglut_assert_ready; + /* Save the display mode if we are creating a menu window */ + if( window->IsMenu && ( ! fgStructure.MenuContext ) ) + fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ; - /* - * XXX fgChooseVisual() is a common part of all three. - * XXX With a little thought, we should be able to greatly - * XXX simplify this. - */ - if( !window->IsMenu ) - window->Window.VisualInfo = fgChooseVisual( ); - else if( fgStructure.MenuContext ) - window->Window.VisualInfo = fgChooseVisual( ); - else - { - /* XXX Why are menus double- and depth-buffered? */ - unsigned int current_DisplayMode = fgState.DisplayMode ; - fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ; - window->Window.VisualInfo = fgChooseVisual( ); + window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs ); + + if( window->IsMenu && ( ! fgStructure.MenuContext ) ) fgState.DisplayMode = current_DisplayMode ; - } - if( ! window->Window.VisualInfo ) + if( ! window->Window.FBConfig ) { /* - * The "fgChooseVisual" returned a null meaning that the visual + * The "fgChooseFBConfig" returned a null meaning that the visual * context is not available. * Try a couple of variations to see if they will work. */ if( !( fgState.DisplayMode & GLUT_DOUBLE ) ) { fgState.DisplayMode |= GLUT_DOUBLE ; - window->Window.VisualInfo = fgChooseVisual( ); + window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs ); fgState.DisplayMode &= ~GLUT_DOUBLE; } - - /* - * GLUT also checks for multi-sampling, but I don't see that - * anywhere else in FREEGLUT so I won't bother with it for the moment. - */ + + if( fgState.DisplayMode & GLUT_MULTISAMPLE ) + { + fgState.DisplayMode &= ~GLUT_MULTISAMPLE ; + window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs ); + fgState.DisplayMode |= GLUT_MULTISAMPLE; + } } + FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.FBConfig != NULL, + "FBConfig with necessary capabilities not found", "fgOpenWindow" ); + + /* Get the X visual. */ + for (i = 0; i < num_FBConfigs; i++) { + visualInfo = glXGetVisualFromFBConfig( fgDisplay.Display, + window->Window.FBConfig[i] ); + if (visualInfo) + break; + } + + FREEGLUT_INTERNAL_ERROR_EXIT( visualInfo != NULL, + "visualInfo could not be retrieved from FBConfig", "fgOpenWindow" ); + /* - * XXX This seems to be abusing an assert() for error-checking. - * XXX It is possible that the visual simply can't be found, - * XXX in which case we should print an error and return a 0 - * XXX for the window id, I think. + * XXX HINT: the masks should be updated when adding/removing callbacks. + * XXX This might speed up message processing. Is that true? + * XXX + * XXX A: Not appreciably, but it WILL make it easier to debug. + * XXX Try tracing old GLUT and try tracing freeglut. Old GLUT + * XXX turns off events that it doesn't need and is a whole lot + * XXX more pleasant to trace. (Think mouse-motion! Tons of + * XXX ``bonus'' GUI events stream in.) */ - assert( window->Window.VisualInfo != NULL ); + winAttr.event_mask = + StructureNotifyMask | SubstructureNotifyMask | ExposureMask | + ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | + VisibilityChangeMask | EnterWindowMask | LeaveWindowMask | + PointerMotionMask | ButtonMotionMask; + winAttr.background_pixmap = None; + winAttr.background_pixel = 0; + winAttr.border_pixel = 0; + + winAttr.colormap = XCreateColormap( + fgDisplay.Display, fgDisplay.RootWindow, + visualInfo->visual, AllocNone + ); - window->State.IsOffscreen = GL_FALSE; - if( fgState.DisplayMode & GLUT_OFFSCREEN ) + mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask; + + if( window->IsMenu || ( gameMode == GL_TRUE ) ) { - window->State.IsOffscreen = GL_TRUE; - window->Window.Pixmap = XCreatePixmap( - fgDisplay.Display, fgDisplay.RootWindow, - w, h, - window->Window.VisualInfo->depth - ); - if( False != window->Window.Pixmap ) - { - window->Window.Handle = glXCreateGLXPixmap( - fgDisplay.Display, - window->Window.VisualInfo, - window->Window.Pixmap - ); - if( False == window->Window.Handle ) - XFreePixmap( fgDisplay.Display, window->Window.Pixmap ); - } + winAttr.override_redirect = True; + mask |= CWOverrideRedirect; } - else - { - /* - * XXX HINT: the masks should be updated when adding/removing callbacks. - * XXX This might speed up message processing. Is that true? - * XXX - * XXX A: Not appreciably, but it WILL make it easier to debug. - * XXX Try tracing old GLUT and try tracing freeglut. Old GLUT - * XXX turns off events that it doesn't need and is a whole lot - * XXX more pleasant to trace. (Think mouse-motion! Tons of - * XXX ``bonus'' GUI events stream in.) - */ - winAttr.event_mask = - StructureNotifyMask | SubstructureNotifyMask | ExposureMask | - ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyRelease | - VisibilityChangeMask | EnterWindowMask | LeaveWindowMask | - PointerMotionMask | ButtonMotionMask; - winAttr.background_pixmap = None; - winAttr.background_pixel = 0; - winAttr.border_pixel = 0; - - winAttr.colormap = XCreateColormap( - fgDisplay.Display, fgDisplay.RootWindow, - window->Window.VisualInfo->visual, AllocNone - ); - mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask; + if( ! positionUse ) + x = y = -1; /* default window position */ + if( ! sizeUse ) + w = h = 300; /* default window size */ - if ( window->IsMenu ) - { - winAttr.override_redirect = True; - mask |= CWOverrideRedirect; - } + window->Window.Handle = XCreateWindow( + fgDisplay.Display, + window->Parent == NULL ? fgDisplay.RootWindow : + window->Parent->Window.Handle, + x, y, w, h, 0, + visualInfo->depth, InputOutput, + visualInfo->visual, mask, + &winAttr + ); - window->Window.Handle = XCreateWindow( - fgDisplay.Display, - window->Parent == NULL ? fgDisplay.RootWindow : - window->Parent->Window.Handle, - x, y, w, h, 0, - window->Window.VisualInfo->depth, InputOutput, - window->Window.VisualInfo->visual, mask, - &winAttr - ); - } /* * The GLX context creation, possibly trying the direct context rendering * or else use the current context if the user has so specified */ + if( window->IsMenu ) { /* @@ -386,45 +1032,30 @@ void fgOpenWindow( SFG_Window* window, const char* title, { fgStructure.MenuContext = (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); - fgStructure.MenuContext->VisualInfo = window->Window.VisualInfo; - fgStructure.MenuContext->Context = glXCreateContext( - fgDisplay.Display, fgStructure.MenuContext->VisualInfo, - NULL, fgState.ForceDirectContext | fgState.TryDirectContext - ); + fgStructure.MenuContext->MContext = fghCreateNewContext( window ); } - /* window->Window.Context = fgStructure.MenuContext->Context; */ - window->Window.Context = glXCreateContext( - fgDisplay.Display, window->Window.VisualInfo, - NULL, fgState.ForceDirectContext | fgState.TryDirectContext - ); + /* window->Window.Context = fgStructure.MenuContext->MContext; */ + window->Window.Context = fghCreateNewContext( window ); } else if( fgState.UseCurrentContext ) { window->Window.Context = glXGetCurrentContext( ); if( ! window->Window.Context ) - window->Window.Context = glXCreateContext( - fgDisplay.Display, window->Window.VisualInfo, - NULL, fgState.ForceDirectContext | fgState.TryDirectContext - ); + window->Window.Context = fghCreateNewContext( window ); } else - window->Window.Context = glXCreateContext( - fgDisplay.Display, window->Window.VisualInfo, - NULL, fgState.ForceDirectContext | fgState.TryDirectContext - ); + window->Window.Context = fghCreateNewContext( window ); - if( fgState.ForceDirectContext && - !glXIsDirect( fgDisplay.Display, window->Window.Context ) ) - fgError( "unable to force direct context rendering for window '%s'", +#if !defined( __FreeBSD__ ) && !defined( __NetBSD__ ) + if( !glXIsDirect( fgDisplay.Display, window->Window.Context ) ) + { + if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT ) + fgError( "Unable to force direct context rendering for window '%s'", title ); - - glXMakeCurrent( - fgDisplay.Display, - window->Window.Handle, - window->Window.Context - ); + } +#endif /* * XXX Assume the new window is visible by default @@ -433,14 +1064,14 @@ void fgOpenWindow( SFG_Window* window, const char* title, window->State.Visible = GL_TRUE; sizeHints.flags = 0; - if ( fgState.Position.Use ) + if ( positionUse ) sizeHints.flags |= USPosition; - if ( fgState.Size.Use ) + if ( sizeUse ) sizeHints.flags |= USSize; /* * Fill in the size hints values now (the x, y, width and height - * settings are obsolote, are there any more WMs that support them?) + * settings are obsolete, are there any more WMs that support them?) * Unless the X servers actually stop supporting these, we should * continue to fill them in. It is *not* our place to tell the user * that they should replace a window manager that they like, and which @@ -453,48 +1084,54 @@ void fgOpenWindow( SFG_Window* window, const char* title, wmHints.flags = StateHint; wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState; - if( GL_FALSE == window->State.IsOffscreen ) - { - /* - * Prepare the window and iconified window names... - */ - XStringListToTextProperty( (char **) &title, 1, &textProperty ); + /* Prepare the window and iconified window names... */ + XStringListToTextProperty( (char **) &title, 1, &textProperty ); - XSetWMProperties( - fgDisplay.Display, - window->Window.Handle, - &textProperty, - &textProperty, - 0, - 0, - &sizeHints, - &wmHints, - NULL - ); - - XSetWMProtocols( fgDisplay.Display, window->Window.Handle, - &fgDisplay.DeleteWindow, 1 ); - - XMapWindow( fgDisplay.Display, window->Window.Handle ); - } - -#elif TARGET_HOST_WIN32 + XSetWMProperties( + fgDisplay.Display, + window->Window.Handle, + &textProperty, + &textProperty, + 0, + 0, + &sizeHints, + &wmHints, + NULL + ); + XFree( textProperty.value ); + + XSetWMProtocols( fgDisplay.Display, window->Window.Handle, + &fgDisplay.DeleteWindow, 1 ); + + glXMakeContextCurrent( + fgDisplay.Display, + window->Window.Handle, + window->Window.Handle, + window->Window.Context + ); + + XMapWindow( fgDisplay.Display, window->Window.Handle ); + + XFree(visualInfo); + +#elif TARGET_HOST_MS_WINDOWS WNDCLASS wc; - int flags; + DWORD flags; + DWORD exFlags = 0; ATOM atom; + int WindowStyle = 0; + + /* Grab the window class we have registered on glutInit(): */ + atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc ); + FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found", + "fgOpenWindow" ); - freeglut_assert_ready; - - /* - * Grab the window class we have registered on glutInit(): - */ - atom = GetClassInfo( fgDisplay.Instance, "FREEGLUT", &wc ); - assert( atom != 0 ); - if( gameMode ) { - assert( window->Parent == NULL ); + FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL, + "Game mode being invoked on a subwindow", + "fgOpenWindow" ); /* * Set the window creation flags appropriately to make the window @@ -504,6 +1141,9 @@ void fgOpenWindow( SFG_Window* window, const char* title, } else { + int worig = w, horig = h; + +#if !defined(_WIN32_WCE) if ( ( ! isSubWindow ) && ( ! window->IsMenu ) ) { /* @@ -515,16 +1155,29 @@ void fgOpenWindow( SFG_Window* window, const char* title, h += (GetSystemMetrics( SM_CYSIZEFRAME ) )*2 + GetSystemMetrics( SM_CYCAPTION ); } +#endif /* defined(_WIN32_WCE) */ - if( ! fgState.Position.Use ) + if( ! positionUse ) { x = CW_USEDEFAULT; y = CW_USEDEFAULT; } - if( ! fgState.Size.Use ) + /* setting State.Width/Height to call resize callback later */ + if( ! sizeUse ) { - w = CW_USEDEFAULT; - h = CW_USEDEFAULT; + if( ! window->IsMenu ) + { + w = CW_USEDEFAULT; + h = CW_USEDEFAULT; + } + else /* fail safe - Windows can make a window of size (0, 0) */ + w = h = 300; /* default window size */ + window->State.Width = window->State.Height = -1; + } + else + { + window->State.Width = worig; + window->State.Height = horig; } /* @@ -534,30 +1187,102 @@ void fgOpenWindow( SFG_Window* window, const char* title, flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; if ( window->IsMenu ) - flags |= WS_POPUP ; + { + flags |= WS_POPUP; + exFlags |= WS_EX_TOOLWINDOW; + } +#if !defined(_WIN32_WCE) else if( window->Parent == NULL ) flags |= WS_OVERLAPPEDWINDOW; +#endif else flags |= WS_CHILD; } - window->Window.Handle = CreateWindow( - "FREEGLUT", - title, - flags, - x, y, w, h, - (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle, - (HMENU) NULL, - fgDisplay.Instance, - (LPVOID) window - ); +#if defined(_WIN32_WCE) + { + wchar_t* wstr = fghWstrFromStr(title); + + window->Window.Handle = CreateWindow( + _T("FREEGLUT"), + wstr, + WS_VISIBLE | WS_POPUP, + 0,0, 240,320, + NULL, + NULL, + fgDisplay.Instance, + (LPVOID) window + ); + + free(wstr); + + SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON); + SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON); + SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR); + MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE); + ShowWindow(window->Window.Handle, SW_SHOW); + UpdateWindow(window->Window.Handle); + } +#else + { + /* xoff and yoff are used to place window relative to current display */ + /* The operation of gamemode also depends on this */ + int xoff=0,yoff=0; + get_display_origin(&xoff,&yoff); + + window->Window.Handle = CreateWindowEx( + exFlags, + _T("FREEGLUT"), + title, + flags, + x+xoff, y+yoff, w, h, + (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle, + (HMENU) NULL, + fgDisplay.Instance, + (LPVOID) window + ); + } +#endif /* defined(_WIN32_WCE) */ + if( !( window->Window.Handle ) ) fgError( "Failed to create a window (%s)!", title ); + /* Make a menu window always on top - fix Feature Request 947118 */ + if( window->IsMenu || gameMode ) + SetWindowPos( + window->Window.Handle, + HWND_TOPMOST, + 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE + ); + + /* Hack to remove the caption (title bar) and/or border + * and all the system menu controls. + */ + WindowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE); + if ( fgState.DisplayMode & GLUT_CAPTIONLESS ) + { + SetWindowLong ( window->Window.Handle, GWL_STYLE, + WindowStyle & ~(WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)); + } + else if ( fgState.DisplayMode & GLUT_BORDERLESS ) + { + SetWindowLong ( window->Window.Handle, GWL_STYLE, + WindowStyle & ~(WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)); + } +/* SetWindowPos(window->Window.Handle, NULL, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); */ + + +#if defined(_WIN32_WCE) + ShowWindow( window->Window.Handle, SW_SHOW ); +#else ShowWindow( window->Window.Handle, fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW ); +#endif /* defined(_WIN32_WCE) */ + UpdateWindow( window->Window.Handle ); - ShowCursor( TRUE ); /* XXX Old comments say "hide cusror"! */ + ShowCursor( TRUE ); /* XXX Old comments say "hide cursor"! */ #endif @@ -578,26 +1303,21 @@ void fgOpenWindow( SFG_Window* window, const char* title, */ void fgCloseWindow( SFG_Window* window ) { - freeglut_assert_ready; +#if TARGET_HOST_POSIX_X11 -#if TARGET_HOST_UNIX_X11 + if( window->Window.Context ) + glXDestroyContext( fgDisplay.Display, window->Window.Context ); + XFree( window->Window.FBConfig ); - glXDestroyContext( fgDisplay.Display, window->Window.Context ); - if( GL_FALSE == window->State.IsOffscreen ) + if( window->Window.Handle ) { XDestroyWindow( fgDisplay.Display, window->Window.Handle ); - else - { - glXDestroyGLXPixmap( fgDisplay.Display, window->Window.Handle ); - XFreePixmap( fgDisplay.Display, window->Window.Pixmap ); } - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + /* XFlush( fgDisplay.Display ); */ /* XXX Shouldn't need this */ -#elif TARGET_HOST_WIN32 +#elif TARGET_HOST_MS_WINDOWS - /* - * Make sure we don't close a window with current context active - */ - if( fgStructure.Window == window ) + /* Make sure we don't close a window with current context active */ + if( fgStructure.CurrentWindow == window ) wglMakeCurrent( NULL, NULL ); /* @@ -633,10 +1353,27 @@ void fgCloseWindow( SFG_Window* window ) */ int FGAPIENTRY glutCreateWindow( const char* title ) { - return fgCreateWindow( NULL, title, fgState.Position.X, fgState.Position.Y, - fgState.Size.X, fgState.Size.Y, GL_FALSE, - GL_FALSE )->ID; + /* XXX GLUT does not exit; it simply calls "glutInit" quietly if the + * XXX application has not already done so. The "freeglut" community + * XXX decided not to go this route (freeglut-developer e-mail from + * XXX Steve Baker, 12/16/04, 4:22 PM CST, "Re: [Freeglut-developer] + * XXX Desired 'freeglut' behaviour when there is no current window" + */ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" ); + + return fgCreateWindow( NULL, title, fgState.Position.Use, + fgState.Position.X, fgState.Position.Y, + fgState.Size.Use, fgState.Size.X, fgState.Size.Y, + GL_FALSE, GL_FALSE )->ID; +} + +#if TARGET_HOST_MS_WINDOWS +int FGAPIENTRY __glutCreateWindowWithExit( const char *title, void (__cdecl *exit_function)(int) ) +{ + __glutExitFunc = exit_function; + return glutCreateWindow( title ); } +#endif /* * This function creates a sub window. @@ -644,18 +1381,41 @@ int FGAPIENTRY glutCreateWindow( const char* title ) int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h ) { int ret = 0; - - if( GL_FALSE == fgStructure.Window->State.IsOffscreen ) + SFG_Window* window = NULL; + SFG_Window* parent = NULL; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" ); + parent = fgWindowByID( parentID ); + freeglut_return_val_if_fail( parent != NULL, 0 ); + if ( x < 0 ) { - SFG_Window* window = NULL; - SFG_Window* parent = NULL; - - freeglut_assert_ready; - parent = fgWindowByID( parentID ); - freeglut_return_val_if_fail( parent != NULL, 0 ); - window = fgCreateWindow( parent, "", x, y, w, h, GL_FALSE, GL_FALSE ); - ret = window->ID; + x = parent->State.Width + x ; + if ( w >= 0 ) x -= w ; } + + if ( w < 0 ) w = parent->State.Width - x + w ; + if ( w < 0 ) + { + x += w ; + w = -w ; + } + + if ( y < 0 ) + { + y = parent->State.Height + y ; + if ( h >= 0 ) y -= h ; + } + + if ( h < 0 ) h = parent->State.Height - y + h ; + if ( h < 0 ) + { + y += h ; + h = -h ; + } + + window = fgCreateWindow( parent, "", GL_TRUE, x, y, GL_TRUE, w, h, GL_FALSE, GL_FALSE ); + ret = window->ID; + return ret; } @@ -664,7 +1424,9 @@ int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h ) */ void FGAPIENTRY glutDestroyWindow( int windowID ) { - SFG_Window* window = fgWindowByID( windowID ); + SFG_Window* window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" ); + window = fgWindowByID( windowID ); freeglut_return_if_fail( window != NULL ); { fgExecutionState ExecState = fgState.ExecState; @@ -680,15 +1442,15 @@ void FGAPIENTRY glutSetWindow( int ID ) { SFG_Window* window = NULL; - freeglut_assert_ready; - if( fgStructure.Window != NULL ) - if( fgStructure.Window->ID == ID ) + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" ); + if( fgStructure.CurrentWindow != NULL ) + if( fgStructure.CurrentWindow->ID == ID ) return; window = fgWindowByID( ID ); if( window == NULL ) { - fgWarning( "glutSetWindow(): window ID %i not found!", ID ); + fgWarning( "glutSetWindow(): window ID %d not found!", ID ); return; } @@ -700,10 +1462,18 @@ void FGAPIENTRY glutSetWindow( int ID ) */ int FGAPIENTRY glutGetWindow( void ) { - freeglut_assert_ready; - if( fgStructure.Window == NULL ) + SFG_Window *win = fgStructure.CurrentWindow; + /* + * Since GLUT did not throw an error if this function was called without a prior call to + * "glutInit", this function shouldn't do so here. Instead let us return a zero. + * See Feature Request "[ 1307049 ] glutInit check". + */ + if ( ! fgState.Initialised ) return 0; - return fgStructure.Window->ID; + + while ( win && win->IsMenu ) + win = win->Parent; + return win ? win->ID : 0; } /* @@ -711,23 +1481,21 @@ int FGAPIENTRY glutGetWindow( void ) */ void FGAPIENTRY glutShowWindow( void ) { - freeglut_assert_ready; - freeglut_assert_window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" ); - if( GL_FALSE == fgStructure.Window->State.IsOffscreen ) - { -#if TARGET_HOST_UNIX_X11 +#if TARGET_HOST_POSIX_X11 - XMapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle ); - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + XMapWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ -#elif TARGET_HOST_WIN32 +#elif TARGET_HOST_MS_WINDOWS - ShowWindow( fgStructure.Window->Window.Handle, SW_SHOW ); + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_SHOW ); #endif - } - fgStructure.Window->State.Redisplay = GL_TRUE; + + fgStructure.CurrentWindow->State.Redisplay = GL_TRUE; } /* @@ -735,29 +1503,27 @@ void FGAPIENTRY glutShowWindow( void ) */ void FGAPIENTRY glutHideWindow( void ) { - freeglut_assert_ready; - freeglut_assert_window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" ); - if( GL_FALSE == fgStructure.Window->State.IsOffscreen ) - { -#if TARGET_HOST_UNIX_X11 +#if TARGET_HOST_POSIX_X11 - if( fgStructure.Window->Parent == NULL ) - XWithdrawWindow( fgDisplay.Display, - fgStructure.Window->Window.Handle, - fgDisplay.Screen ); - else - XUnmapWindow( fgDisplay.Display, - fgStructure.Window->Window.Handle ); - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + if( fgStructure.CurrentWindow->Parent == NULL ) + XWithdrawWindow( fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + fgDisplay.Screen ); + else + XUnmapWindow( fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ -#elif TARGET_HOST_WIN32 +#elif TARGET_HOST_MS_WINDOWS - ShowWindow( fgStructure.Window->Window.Handle, SW_HIDE ); + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_HIDE ); #endif - } - fgStructure.Window->State.Redisplay = GL_FALSE; + + fgStructure.CurrentWindow->State.Redisplay = GL_FALSE; } /* @@ -765,25 +1531,23 @@ void FGAPIENTRY glutHideWindow( void ) */ void FGAPIENTRY glutIconifyWindow( void ) { - freeglut_assert_ready; - freeglut_assert_window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" ); - fgStructure.Window->State.Visible = GL_FALSE; - if( GL_FALSE == fgStructure.Window->State.IsOffscreen ) - { -#if TARGET_HOST_UNIX_X11 + fgStructure.CurrentWindow->State.Visible = GL_FALSE; +#if TARGET_HOST_POSIX_X11 - XIconifyWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, - fgDisplay.Screen ); - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + XIconifyWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, + fgDisplay.Screen ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ -#elif TARGET_HOST_WIN32 +#elif TARGET_HOST_MS_WINDOWS - ShowWindow( fgStructure.Window->Window.Handle, SW_MINIMIZE ); + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_MINIMIZE ); #endif - } - fgStructure.Window->State.Redisplay = GL_FALSE; + + fgStructure.CurrentWindow->State.Redisplay = GL_FALSE; } /* @@ -791,31 +1555,37 @@ void FGAPIENTRY glutIconifyWindow( void ) */ void FGAPIENTRY glutSetWindowTitle( const char* title ) { - freeglut_assert_ready; - freeglut_assert_window; - if( ! fgStructure.Window->Parent && - ( GL_FALSE == fgStructure.Window->State.IsOffscreen ) ) + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" ); + if( ! fgStructure.CurrentWindow->Parent ) { -#if TARGET_HOST_UNIX_X11 +#if TARGET_HOST_POSIX_X11 XTextProperty text; - + text.value = (unsigned char *) title; text.encoding = XA_STRING; text.format = 8; text.nitems = strlen( title ); - + XSetWMName( fgDisplay.Display, - fgStructure.Window->Window.Handle, + fgStructure.CurrentWindow->Window.Handle, &text ); - - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ -#elif TARGET_HOST_WIN32 + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ - SetWindowText( fgStructure.Window->Window.Handle, title ); +#elif TARGET_HOST_MS_WINDOWS +# ifdef _WIN32_WCE + { + wchar_t* wstr = fghWstrFromStr(title); + SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr ); + free(wstr); + } +# else + SetWindowText( fgStructure.CurrentWindow->Window.Handle, title ); +# endif #endif } @@ -826,16 +1596,15 @@ void FGAPIENTRY glutSetWindowTitle( const char* title ) */ void FGAPIENTRY glutSetIconTitle( const char* title ) { - freeglut_assert_ready; - freeglut_assert_window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" ); - if( ! fgStructure.Window->Parent && - GL_FALSE == fgStructure.Window->State.IsOffscreen ) + if( ! fgStructure.CurrentWindow->Parent ) { -#if TARGET_HOST_UNIX_X11 +#if TARGET_HOST_POSIX_X11 XTextProperty text; - + text.value = (unsigned char *) title; text.encoding = XA_STRING; text.format = 8; @@ -843,15 +1612,22 @@ void FGAPIENTRY glutSetIconTitle( const char* title ) XSetWMIconName( fgDisplay.Display, - fgStructure.Window->Window.Handle, + fgStructure.CurrentWindow->Window.Handle, &text ); XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ -#elif TARGET_HOST_WIN32 - - SetWindowText( fgStructure.Window->Window.Handle, title ); +#elif TARGET_HOST_MS_WINDOWS +# ifdef _WIN32_WCE + { + wchar_t* wstr = fghWstrFromStr(title); + SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr ); + free(wstr); + } +# else + SetWindowText( fgStructure.CurrentWindow->Window.Handle, title ); +# endif #endif } @@ -862,16 +1638,18 @@ void FGAPIENTRY glutSetIconTitle( const char* title ) */ void FGAPIENTRY glutReshapeWindow( int width, int height ) { - freeglut_assert_ready; - freeglut_assert_window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" ); - /* XXX Could delete/create/set-window-id for offscreen. */ - if( GL_FALSE == fgStructure.Window->State.IsOffscreen ) + if (glutGet(GLUT_FULL_SCREEN)) { - fgStructure.Window->State.NeedToResize = GL_TRUE; - fgStructure.Window->State.Width = width ; - fgStructure.Window->State.Height = height; + /* Leave full screen state before resizing. */ + glutFullScreenToggle(); } + + fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; + fgStructure.CurrentWindow->State.Width = width ; + fgStructure.CurrentWindow->State.Height = height; } /* @@ -879,33 +1657,39 @@ void FGAPIENTRY glutReshapeWindow( int width, int height ) */ void FGAPIENTRY glutPositionWindow( int x, int y ) { - freeglut_assert_ready; - freeglut_assert_window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" ); - if( GL_FALSE == fgStructure.Window->State.IsOffscreen ) + if (glutGet(GLUT_FULL_SCREEN)) { -#if TARGET_HOST_UNIX_X11 + /* Leave full screen state before moving. */ + glutFullScreenToggle(); + } - XMoveWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, - x, y ); - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ +#if TARGET_HOST_POSIX_X11 + + XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, + x, y ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ -#elif TARGET_HOST_WIN32 +#elif TARGET_HOST_MS_WINDOWS + { RECT winRect; - - GetWindowRect( fgStructure.Window->Window.Handle, &winRect ); + + /* "GetWindowRect" returns the pixel coordinates of the outside of the window */ + GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect ); MoveWindow( - fgStructure.Window->Window.Handle, + fgStructure.CurrentWindow->Window.Handle, x, y, winRect.right - winRect.left, winRect.bottom - winRect.top, TRUE ); + } #endif - } } /* @@ -913,26 +1697,23 @@ void FGAPIENTRY glutPositionWindow( int x, int y ) */ void FGAPIENTRY glutPushWindow( void ) { - freeglut_assert_ready; - freeglut_assert_window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" ); - if( GL_FALSE == fgStructure.Window->State.IsOffscreen ) - { -#if TARGET_HOST_UNIX_X11 +#if TARGET_HOST_POSIX_X11 - XLowerWindow( fgDisplay.Display, fgStructure.Window->Window.Handle ); + XLowerWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); -#elif TARGET_HOST_WIN32 +#elif TARGET_HOST_MS_WINDOWS - SetWindowPos( - fgStructure.Window->Window.Handle, - HWND_BOTTOM, - 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE - ); + SetWindowPos( + fgStructure.CurrentWindow->Window.Handle, + HWND_BOTTOM, + 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE + ); #endif - } } /* @@ -940,26 +1721,23 @@ void FGAPIENTRY glutPushWindow( void ) */ void FGAPIENTRY glutPopWindow( void ) { - freeglut_assert_ready; - freeglut_assert_window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" ); - if( GL_FALSE == fgStructure.Window->State.IsOffscreen ) - { -#if TARGET_HOST_UNIX_X11 +#if TARGET_HOST_POSIX_X11 - XRaiseWindow( fgDisplay.Display, fgStructure.Window->Window.Handle ); + XRaiseWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); -#elif TARGET_HOST_WIN32 +#elif TARGET_HOST_MS_WINDOWS - SetWindowPos( - fgStructure.Window->Window.Handle, - HWND_TOP, - 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE - ); + SetWindowPos( + fgStructure.CurrentWindow->Window.Handle, + HWND_TOP, + 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE + ); #endif - } } /* @@ -967,42 +1745,29 @@ void FGAPIENTRY glutPopWindow( void ) */ void FGAPIENTRY glutFullScreen( void ) { - freeglut_assert_ready; - freeglut_assert_window; + SFG_Window *win; - if( GL_FALSE == fgStructure.Window->State.IsOffscreen ) - { -#if TARGET_HOST_UNIX_X11 - int x, y; - Window w; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); - XMoveResizeWindow( - fgDisplay.Display, - fgStructure.Window->Window.Handle, - 0, 0, - fgDisplay.ScreenWidth, - fgDisplay.ScreenHeight - ); + win = fgStructure.CurrentWindow; - XFlush( fgDisplay.Display ); /* This is needed */ +#if TARGET_HOST_POSIX_X11 + if(!glutGet(GLUT_FULL_SCREEN)) { + if(fghToggleFullscreen() != -1) { + win->State.IsFullscreen = GL_TRUE; + } + } - XTranslateCoordinates( - fgDisplay.Display, - fgStructure.Window->Window.Handle, - fgDisplay.RootWindow, - 0, 0, &x, &y, &w - ); +#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */ - if (x || y) - { - XMoveWindow( - fgDisplay.Display, - fgStructure.Window->Window.Handle, - -x, -y - ); - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ - } -#elif TARGET_HOST_WIN32 + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before resizing. */ + glutFullScreenToggle(); + } + + { RECT rect; /* For fullscreen mode, force the top-left corner to 0,0 @@ -1012,8 +1777,9 @@ void FGAPIENTRY glutFullScreen( void ) rect.left = 0; rect.top = 0; - rect.right = fgDisplay.ScreenWidth; - rect.bottom = fgDisplay.ScreenHeight; + get_display_origin(&rect.left,&rect.top); + rect.right = fgDisplay.ScreenWidth+rect.left; + rect.bottom = fgDisplay.ScreenHeight+rect.top; AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, FALSE ); @@ -1025,7 +1791,7 @@ void FGAPIENTRY glutFullScreen( void ) * SWP_NOZORDER Retains the current Z order (ignore 2nd param) */ - SetWindowPos( fgStructure.Window->Window.Handle, + SetWindowPos( fgStructure.CurrentWindow->Window.Handle, HWND_TOP, rect.left, rect.top, @@ -1033,9 +1799,33 @@ void FGAPIENTRY glutFullScreen( void ) rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOZORDER - ); + ); + + win->State.IsFullscreen = GL_TRUE; + } #endif +} + +/* + * Toggle the window's full screen state. + */ +void FGAPIENTRY glutFullScreenToggle( void ) +{ + SFG_Window *win; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" ); + + win = fgStructure.CurrentWindow; + +#if TARGET_HOST_POSIX_X11 + if(fghToggleFullscreen() != -1) { + win->State.IsFullscreen = !win->State.IsFullscreen; } +#elif TARGET_HOST_MS_WINDOWS + glutFullScreen(); + win->State.IsFullscreen = !win->State.IsFullscreen; +#endif } /* @@ -1043,12 +1833,16 @@ void FGAPIENTRY glutFullScreen( void ) */ void* FGAPIENTRY glutGetWindowData( void ) { - return fgStructure.Window->UserData; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" ); + return fgStructure.CurrentWindow->UserData; } void FGAPIENTRY glutSetWindowData(void* data) { - fgStructure.Window->UserData = data; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" ); + fgStructure.CurrentWindow->UserData = data; } /*** END OF FILE ***/