X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ffreeglut_window.c;h=03a3b255d81045ef38d81c864b20c39990b89804;hb=8fb7b342a32cb2336b5c3752c68714b47ac7c63e;hp=3c7bfb613586027b0ecc196609b31e66e7aa6659;hpb=8c2099b6c2e5c34794d9648a7122dc54a04a1a1a;p=freeglut diff --git a/src/freeglut_window.c b/src/freeglut_window.c index 3c7bfb6..03a3b25 100644 --- a/src/freeglut_window.c +++ b/src/freeglut_window.c @@ -25,9 +25,14 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#define FREEGLUT_BUILDING_LIB #include #include "freeglut_internal.h" +#if TARGET_HOST_POSIX_X11 +#include /* LONG_MAX */ +#endif + #if defined(_WIN32_WCE) # include # ifdef FREEGLUT_LIB_PRAGMAS @@ -128,19 +133,28 @@ GLXFBConfig* fgChooseFBConfig( void ) ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 ); } - if( fgState.DisplayMode & GLUT_AUX1 ) - ATTRIB_VAL( GLX_AUX_BUFFERS, 1 ); - if( fgState.DisplayMode & GLUT_AUX2 ) - ATTRIB_VAL( GLX_AUX_BUFFERS, 2 ); - if( fgState.DisplayMode & GLUT_AUX3 ) - ATTRIB_VAL( GLX_AUX_BUFFERS, 3 ); if( fgState.DisplayMode & GLUT_AUX4 ) - ATTRIB_VAL( GLX_AUX_BUFFERS, 4 ); - if ( fgState.DisplayMode & GLUT_MULTISAMPLE ) { - ATTRIB_VAL( GLX_SAMPLE_BUFFERS, 1 ); + ATTRIB_VAL(GLX_AUX_BUFFERS, 4); + } + else if( fgState.DisplayMode & GLUT_AUX3 ) + { + ATTRIB_VAL(GLX_AUX_BUFFERS, 3); + } + else if( fgState.DisplayMode & GLUT_AUX2 ) + { + ATTRIB_VAL(GLX_AUX_BUFFERS, 2); + } + else if( fgState.DisplayMode & GLUT_AUX1 ) /* NOTE: Same as GLUT_AUX! */ + { + ATTRIB_VAL(GLX_AUX_BUFFERS, fgState.AuxiliaryBufferNumber); } + if (fgState.DisplayMode & GLUT_MULTISAMPLE) + { + ATTRIB_VAL(GLX_SAMPLE_BUFFERS, 1) + ATTRIB_VAL(GLX_SAMPLES, fgState.SampleNumber) + } /* Push a null at the end of the list */ ATTRIB( None ); @@ -249,7 +263,7 @@ GLXFBConfig* fgChooseFBConfig( void ) return fbconfig; } } -#endif +#endif /* TARGET_HOST_POSIX_X11 */ /* * Setup the pixel format for a Win32 window @@ -278,6 +292,81 @@ typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAt #define WGL_SAMPLES_ARB 0x2042 +#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_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#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 ERROR_INVALID_VERSION_ARB 0x2095 +#endif + + +void fgNewWGLCreateContext( SFG_Window* window ) +{ + PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetEntensionsStringARB; + HGLRC context; + int attribs[7]; + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; + const char * pWglExtString; + + /* If nothing fancy has been required, leave the context as it is */ + if ( fgState.MajorVersion == 1 && fgState.MinorVersion == 0 && fgState.ContextFlags == 0 ) + { + return; + } + + wglMakeCurrent( window->Window.Device, + window->Window.Context ); + + wglGetEntensionsStringARB=(PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); + if ( wglGetEntensionsStringARB == NULL ) + { + return; + } + + pWglExtString=wglGetEntensionsStringARB(window->Window.Device); + if (( pWglExtString == NULL ) || ( strstr(pWglExtString, "WGL_ARB_create_context") == NULL )) + { + return; + } + + /* new context creation */ + attribs[0] = WGL_CONTEXT_MAJOR_VERSION_ARB; + attribs[1] = fgState.MajorVersion; + attribs[2] = WGL_CONTEXT_MINOR_VERSION_ARB; + attribs[3] = fgState.MinorVersion; + attribs[4] = WGL_CONTEXT_FLAGS_ARB; + attribs[5] = ((fgState.ContextFlags & GLUT_DEBUG) ? WGL_CONTEXT_DEBUG_BIT_ARB : 0) | + ((fgState.ContextFlags & GLUT_FORWARD_COMPATIBLE) ? WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB : 0); + attribs[6] = 0; + + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress( "wglCreateContextAttribsARB" ); + if ( wglCreateContextAttribsARB == NULL ) + { + fgError( "wglCreateContextAttribsARB not found" ); + } + + context = wglCreateContextAttribsARB( window->Window.Device, 0, attribs ); + if ( context == NULL ) + { + fgError( "Unable to create OpenGL %d.%d context (flags %x)", + fgState.MajorVersion, fgState.MinorVersion, fgState.ContextFlags ); + } + + wglMakeCurrent( NULL, NULL ); + wglDeleteContext( window->Window.Context ); + window->Window.Context = context; +} + + GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, unsigned char layer_type ) { @@ -347,8 +436,8 @@ GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, pfd.cAuxBuffers = 3; else if( fgState.DisplayMode & GLUT_AUX2 ) pfd.cAuxBuffers = 2; - else if( fgState.DisplayMode & GLUT_AUX1 ) - pfd.cAuxBuffers = 1; + else if( fgState.DisplayMode & GLUT_AUX1 ) /* NOTE: Same as GLUT_AUX! */ + pfd.cAuxBuffers = fgState.AuxiliaryBufferNumber; else pfd.cAuxBuffers = 0; @@ -371,17 +460,16 @@ GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, HWND hWnd; HDC hDC, hDC_before=wglGetCurrentDC(); WNDCLASS wndCls; - ATOM atom; /* 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"); - atom = RegisterClass( &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((LPCSTR)atom, _T(""), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW , 0,0,0,0, 0, 0, fgDisplay.Instance, 0 ); + 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 ); @@ -418,7 +506,7 @@ GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, pAttributes[iCounter++]=WGL_DOUBLE_BUFFER_ARB; pAttributes[iCounter++]=(fgState.DisplayMode & GLUT_DOUBLE)!=0; pAttributes[iCounter++]=WGL_SAMPLE_BUFFERS_ARB; pAttributes[iCounter++]=GL_TRUE; - pAttributes[iCounter++]=WGL_SAMPLES_ARB; pAttributes[iCounter++]=4; + pAttributes[iCounter++]=WGL_SAMPLES_ARB; pAttributes[iCounter++]=fgState.SampleNumber; pAttributes[iCounter++]=0; pAttributes[iCounter++]=0; /* terminator */ bValid = wglChoosePixelFormatARBProc(window->Window.Device,pAttributes,fAttributes,1,&iPixelFormat,&numFormats); @@ -478,6 +566,90 @@ void fgSetWindow ( SFG_Window *window ) } + +#if TARGET_HOST_POSIX_X11 + +#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_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 + +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 attribs[7]; + CreateContextAttribsProc createContextAttribs; + + /* If nothing fancy has been required, simply use the old context creation GLX API entry */ + if ( fgState.MajorVersion == 1 && fgState.MinorVersion == 0 && fgState.ContextFlags == 0) + { + context = glXCreateNewContext( dpy, config, render_type, share_list, direct ); + if ( context == NULL ) { + fgError( "could not create new OpenGL context" ); + } + 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" ); + } + + attribs[0] = GLX_CONTEXT_MAJOR_VERSION_ARB; + attribs[1] = fgState.MajorVersion; + attribs[2] = GLX_CONTEXT_MINOR_VERSION_ARB; + attribs[3] = fgState.MinorVersion; + attribs[4] = GLX_CONTEXT_FLAGS_ARB; + attribs[5] = ((fgState.ContextFlags & GLUT_DEBUG) ? GLX_CONTEXT_DEBUG_BIT_ARB : 0) | + ((fgState.ContextFlags & GLUT_FORWARD_COMPATIBLE) ? GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB : 0); + attribs[6] = 0; + + createContextAttribs = (CreateContextAttribsProc) fghGetProcAddress( "glXCreateContextAttribsARB" ); + if ( createContextAttribs == NULL ) { + fgError( "glXCreateContextAttribsARB not found" ); + } + + context = createContextAttribs( dpy, config, share_list, direct, attribs ); + if ( context == NULL ) { + fgError( "could not create new OpenGL %d.%d context (flags %x)", + fgState.MajorVersion, fgState.MinorVersion, fgState.ContextFlags ); + } + return context; +} +#endif + + /* * Opens a window. Requires a SFG_Window object created and attached * to the freeglut structure. OpenGL context is created here. @@ -494,7 +666,6 @@ void fgOpenWindow( SFG_Window* window, const char* title, XSizeHints sizeHints; XWMHints wmHints; unsigned long mask; - int renderType; /* GLX_RGBA_TYPE or GLX_COLOR_INDEX_TYPE */ unsigned int current_DisplayMode = fgState.DisplayMode ; /* Save the display mode if we are creating a menu window */ @@ -587,21 +758,6 @@ void fgOpenWindow( SFG_Window* window, const char* title, * or else use the current context if the user has so specified */ - /* Set renderType. */ - if( window->IsMenu && ( ! fgStructure.MenuContext ) ) - { - /* Display mode has been set to GLUT_RGB. */ - renderType = GLX_RGBA_TYPE; - } - else if (fgState.DisplayMode & GLUT_INDEX) - { - renderType = GLX_COLOR_INDEX_TYPE; - } - else - { - renderType = GLX_RGBA_TYPE; - } - if( window->IsMenu ) { /* @@ -612,33 +768,21 @@ void fgOpenWindow( SFG_Window* window, const char* title, { fgStructure.MenuContext = (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); - fgStructure.MenuContext->Context = glXCreateNewContext( - fgDisplay.Display, *(window->Window.FBConfig), renderType, - NULL, ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT ) - ); + fgStructure.MenuContext->MContext = fghCreateNewContext( window ); } /* window->Window.Context = fgStructure.MenuContext->MContext; */ - window->Window.Context = glXCreateContext( - fgDisplay.Display, window->Window.FBConfig, renderType, - NULL, ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT ) - ); + window->Window.Context = fghCreateNewContext( window ); } else if( fgState.UseCurrentContext ) { window->Window.Context = glXGetCurrentContext( ); if( ! window->Window.Context ) - window->Window.Context = glXCreateNewContext( - fgDisplay.Display, window->Window.FBConfig, renderType, - NULL, ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT ) - ); + window->Window.Context = fghCreateNewContext( window ); } else - window->Window.Context = glXCreateNewContext( - fgDisplay.Display, window->Window.FBConfig, renderType, - NULL, ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT ) - ); + window->Window.Context = fghCreateNewContext( window ); #if !defined( __FreeBSD__ ) && !defined( __NetBSD__ ) if( !glXIsDirect( fgDisplay.Display, window->Window.Context ) ) @@ -646,9 +790,6 @@ void fgOpenWindow( SFG_Window* window, const char* title, if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT ) fgError( "Unable to force direct context rendering for window '%s'", title ); - else if( fgState.DirectContext == GLUT_TRY_DIRECT_CONTEXT ) - fgWarning( "Unable to create direct context rendering for window '%s'\nThis may hurt performance.", - title ); } #endif @@ -858,8 +999,8 @@ void fgOpenWindow( SFG_Window* window, const char* title, 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); +/* SetWindowPos(window->Window.Handle, NULL, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); */ #if defined(_WIN32_WCE) @@ -893,10 +1034,11 @@ void fgCloseWindow( SFG_Window* window ) { #if TARGET_HOST_POSIX_X11 - glXDestroyContext( fgDisplay.Display, window->Window.Context ); + if( window->Window.Context ) + glXDestroyContext( fgDisplay.Display, window->Window.Context ); XFree( window->Window.FBConfig ); XDestroyWindow( fgDisplay.Display, window->Window.Handle ); - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + /* XFlush( fgDisplay.Display ); */ /* XXX Shouldn't need this */ #elif TARGET_HOST_MS_WINDOWS @@ -951,6 +1093,14 @@ int FGAPIENTRY glutCreateWindow( const char* title ) GL_FALSE, GL_FALSE )->ID; } +#ifdef _WIN32 +int FGAPIENTRY __glutCreateWindowWithExit( const char *title, void (__cdecl *exitfunc)(int) ) +{ + __glutExitFunc = exitfunc; + return glutCreateWindow( title ); +} +#endif + /* * This function creates a sub window. */ @@ -1217,6 +1367,12 @@ void FGAPIENTRY glutReshapeWindow( int width, int height ) FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" ); FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" ); + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before resizing. */ + glutFullScreenToggle(); + } + fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; fgStructure.CurrentWindow->State.Width = width ; fgStructure.CurrentWindow->State.Height = height; @@ -1230,6 +1386,12 @@ void FGAPIENTRY glutPositionWindow( int x, int y ) FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" ); FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" ); + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before moving. */ + glutFullScreenToggle(); + } + #if TARGET_HOST_POSIX_X11 XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, @@ -1312,37 +1474,32 @@ void FGAPIENTRY glutFullScreen( void ) FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); + if (glutGet(GLUT_FULL_SCREEN)) { -#if TARGET_HOST_POSIX_X11 - int x, y; - Window w; + /* Leave full screen state before resizing. */ + glutFullScreenToggle(); + } - XMoveResizeWindow( - fgDisplay.Display, - fgStructure.CurrentWindow->Window.Handle, - 0, 0, - fgDisplay.ScreenWidth, - fgDisplay.ScreenHeight - ); + { +#if TARGET_HOST_POSIX_X11 - XFlush( fgDisplay.Display ); /* This is needed */ + Status status; /* Returned by XGetWindowAttributes(), not checked. */ + XWindowAttributes attributes; - XTranslateCoordinates( - fgDisplay.Display, - fgStructure.CurrentWindow->Window.Handle, - fgDisplay.RootWindow, - 0, 0, &x, &y, &w - ); + status = XGetWindowAttributes(fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &attributes); + /* + * The "x" and "y" members of "attributes" are the window's coordinates + * relative to its parent, i.e. to the decoration window. + */ + XMoveResizeWindow(fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + -attributes.x, + -attributes.y, + fgDisplay.ScreenWidth, + fgDisplay.ScreenHeight); - if (x || y) - { - XMoveWindow( - fgDisplay.Display, - fgStructure.CurrentWindow->Window.Handle, - -x, -y - ); - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ - } #elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */ RECT rect; @@ -1380,6 +1537,61 @@ void FGAPIENTRY glutFullScreen( void ) } /* + * Toggle the window's full screen state. + */ +void FGAPIENTRY glutFullScreenToggle( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" ); + + { +#if TARGET_HOST_POSIX_X11 + + if (fgDisplay.StateFullScreen != None) + { + XEvent xevent; + long event_mask; + int status; + + xevent.type = ClientMessage; + xevent.xclient.type = ClientMessage; + xevent.xclient.serial = 0; + xevent.xclient.send_event = True; + xevent.xclient.display = fgDisplay.Display; + xevent.xclient.window = fgStructure.CurrentWindow->Window.Handle; + xevent.xclient.message_type = fgDisplay.State; + xevent.xclient.format = 32; + xevent.xclient.data.l[0] = 2; /* _NET_WM_STATE_TOGGLE */ + xevent.xclient.data.l[1] = fgDisplay.StateFullScreen; + xevent.xclient.data.l[2] = 0; + xevent.xclient.data.l[3] = 0; + xevent.xclient.data.l[4] = 0; + + /*** Don't really understand how event masks work... ***/ + event_mask = SubstructureRedirectMask | SubstructureNotifyMask; + + status = XSendEvent(fgDisplay.Display, + fgDisplay.RootWindow, + False, + event_mask, + &xevent); + FREEGLUT_INTERNAL_ERROR_EXIT(status != 0, + "XSendEvent failed", + "glutFullScreenToggle"); + } + else +#endif + { + /* + * If the window manager is not Net WM compliant, fall back to legacy + * behaviour. + */ + glutFullScreen(); + } + } +} + +/* * A.Donev: Set and retrieve the window's user data */ void* FGAPIENTRY glutGetWindowData( void )