X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ffreeglut_init.c;h=5b5771b7c8f1e66a359325f2da2c827bc01c0754;hb=34f0aa01c95a8e6843069d5b9e4b2e7a7bbe1e53;hp=fbf906508c9923b2c7af92a46ed61226875756ac;hpb=7fdce1253e14170b6cb933f13c1f2a1644c93793;p=freeglut diff --git a/src/freeglut_init.c b/src/freeglut_init.c index fbf9065..5b5771b 100644 --- a/src/freeglut_init.c +++ b/src/freeglut_init.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 + /* * TODO BEFORE THE STABLE RELEASE: * @@ -65,11 +70,7 @@ SFG_State fgState = { { -1, -1, GL_FALSE }, /* Position */ 0, /* FPSInterval */ 0, /* SwapCount */ 0, /* SwapTime */ -#if TARGET_HOST_MS_WINDOWS - { 0, GL_FALSE }, /* Time */ -#else - { { 0, 0 }, GL_FALSE }, -#endif + 0, /* Time */ { NULL, NULL }, /* Timers */ { NULL, NULL }, /* FreeTimers */ NULL, /* IdleCallback */ @@ -83,12 +84,160 @@ SFG_State fgState = { { -1, -1, GL_FALSE }, /* Position */ GLUT_EXEC_STATE_INIT, /* ExecState */ NULL, /* ProgramName */ GL_FALSE, /* JoysticksInitialised */ - GL_FALSE /* InputDevsInitialised */ + 0, /* NumActiveJoysticks */ + GL_FALSE, /* InputDevsInitialised */ + 0, /* MouseWheelTicks */ + 1, /* AuxiliaryBufferNumber */ + 4, /* SampleNumber */ + 1, /* MajorVersion */ + 0, /* MinorVersion */ + 0, /* ContextFlags */ + 0, /* ContextProfile */ + NULL, /* ErrorFunc */ + NULL /* WarningFunc */ }; /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ +#if TARGET_HOST_POSIX_X11 + +/* Return the atom associated with "name". */ +static Atom fghGetAtom(const char * name) +{ + return XInternAtom(fgDisplay.Display, name, False); +} + +/* + * Check if "property" is set on "window". The property's values are returned + * through "data". If the property is set and is of type "type", return the + * number of elements in "data". Return zero otherwise. In both cases, use + * "Xfree()" to free "data". + */ +static int fghGetWindowProperty(Window window, + Atom property, + Atom type, + unsigned char ** data) +{ + /* + * Caller always has to use "Xfree()" to free "data", since + * "XGetWindowProperty() always allocates one extra byte in prop_return + * [i.e. "data"] (even if the property is zero length) [..]". + */ + + int status; /* Returned by "XGetWindowProperty". */ + + Atom type_returned; + int temp_format; /* Not used. */ + unsigned long number_of_elements; + unsigned long temp_bytes_after; /* Not used. */ + + + status = XGetWindowProperty(fgDisplay.Display, + window, + property, + 0, + LONG_MAX, + False, + type, + &type_returned, + &temp_format, + &number_of_elements, + &temp_bytes_after, + data); + + FREEGLUT_INTERNAL_ERROR_EXIT(status == Success, + "XGetWindowProperty failled", + "fghGetWindowProperty"); + + if (type_returned != type) + { + number_of_elements = 0; + } + + return number_of_elements; +} + +/* Check if the window manager is NET WM compliant. */ +static int fghNetWMSupported(void) +{ + Atom wm_check; + Window ** window_ptr_1; + + int number_of_windows; + int net_wm_supported; + + + net_wm_supported = 0; + + wm_check = fghGetAtom("_NET_SUPPORTING_WM_CHECK"); + window_ptr_1 = malloc(sizeof(Window *)); + + /* + * Check that the window manager has set this property on the root window. + * The property must be the ID of a child window. + */ + number_of_windows = fghGetWindowProperty(fgDisplay.RootWindow, + wm_check, + XA_WINDOW, + (unsigned char **) window_ptr_1); + if (number_of_windows == 1) + { + Window ** window_ptr_2; + + window_ptr_2 = malloc(sizeof(Window *)); + + /* Check that the window has the same property set to the same value. */ + number_of_windows = fghGetWindowProperty(**window_ptr_1, + wm_check, + XA_WINDOW, + (unsigned char **) window_ptr_2); + if ((number_of_windows == 1) && (**window_ptr_1 == **window_ptr_2)) + { + /* NET WM compliant */ + net_wm_supported = 1; + } + + XFree(*window_ptr_2); + free(window_ptr_2); + } + + XFree(*window_ptr_1); + free(window_ptr_1); + + return net_wm_supported; +} + +/* Check if "hint" is present in "property" for "window". */ +int fgHintPresent(Window window, Atom property, Atom hint) +{ + Atom *atoms; + int number_of_atoms; + int supported; + int i; + + supported = 0; + + number_of_atoms = fghGetWindowProperty(window, + property, + XA_ATOM, + (unsigned char **) &atoms); + for (i = 0; i < number_of_atoms; i++) + { + if (atoms[i] == hint) + { + supported = 1; + break; + } + } + + XFree(atoms); + return supported; +} + +#endif /* TARGET_HOST_POSIX_X11 */ + + /* * A call to this function should initialize all the display stuff... */ @@ -131,11 +280,32 @@ static void fghInitialize( const char* displayName ) fgDisplay.Connection = ConnectionNumber( fgDisplay.Display ); /* Create the window deletion atom */ - fgDisplay.DeleteWindow = XInternAtom( - fgDisplay.Display, - "WM_DELETE_WINDOW", - FALSE - ); + fgDisplay.DeleteWindow = fghGetAtom("WM_DELETE_WINDOW"); + + /* Create the state and full screen atoms */ + fgDisplay.State = None; + fgDisplay.StateFullScreen = None; + + if (fghNetWMSupported()) + { + const Atom supported = fghGetAtom("_NET_SUPPORTED"); + const Atom state = fghGetAtom("_NET_WM_STATE"); + + /* Check if the state hint is supported. */ + if (fgHintPresent(fgDisplay.RootWindow, supported, state)) + { + const Atom full_screen = fghGetAtom("_NET_WM_STATE_FULLSCREEN"); + + fgDisplay.State = state; + + /* Check if the window manager supports full screen. */ + /** Check "_NET_WM_ALLOWED_ACTIONS" on our window instead? **/ + if (fgHintPresent(fgDisplay.RootWindow, supported, full_screen)) + { + fgDisplay.StateFullScreen = full_screen; + } + } + } #elif TARGET_HOST_MS_WINDOWS @@ -144,7 +314,7 @@ static void fghInitialize( const char* displayName ) /* What we need to do is to initialize the fgDisplay global structure here. */ fgDisplay.Instance = GetModuleHandle( NULL ); - + fgDisplay.DisplayName= displayName ? strdup(displayName) : 0 ; atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc ); if( atom == 0 ) @@ -196,7 +366,24 @@ static void fghInitialize( const char* displayName ) ReleaseDC( desktop, context ); } - + /* If we have a DisplayName try to use it for metrics */ + if( fgDisplay.DisplayName ) + { + HDC context = CreateDC(fgDisplay.DisplayName,0,0,0); + if( context ) + { + fgDisplay.ScreenWidth = GetDeviceCaps( context, HORZRES ); + fgDisplay.ScreenHeight = GetDeviceCaps( context, VERTRES ); + fgDisplay.ScreenWidthMM = GetDeviceCaps( context, HORZSIZE ); + fgDisplay.ScreenHeightMM = GetDeviceCaps( context, VERTSIZE ); + DeleteDC(context); + } + else + fgWarning("fghInitialize: " + "CreateDC failed, Screen size info may be incorrect\n" + "This is quite likely caused by a bad '-display' parameter"); + + } /* Set the timer granularity to 1 ms */ timeBeginPeriod ( 1 ); @@ -204,6 +391,15 @@ static void fghInitialize( const char* displayName ) fgState.Initialised = GL_TRUE; + /* Avoid registering atexit callback on Win32 as it results in an access + * violation due to calling into a module which has been unloaded. + * Any cleanup isn't needed on Windows anyway, the OS takes care of it.c + * see: http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx + */ +#if ( TARGET_HOST_MS_WINDOWS == 0 ) + atexit(fgDeinitialize); +#endif + /* InputDevice uses GlutTimerFunc(), so fgState.Initialised must be TRUE */ fgInitialiseInputDevices(); } @@ -217,11 +413,14 @@ void fgDeinitialize( void ) if( !fgState.Initialised ) { - fgWarning( "fgDeinitialize(): " - "no valid initialization has been performed" ); return; } + /* If we're in game mode, we want to leave game mode */ + if( fgStructure.GameModeWindow ) { + glutLeaveGameMode(); + } + /* If there was a menu created, destroy the rendering context */ if( fgStructure.MenuContext ) { @@ -257,6 +456,13 @@ void fgDeinitialize( void ) fgState.JoysticksInitialised = GL_FALSE; fgState.InputDevsInitialised = GL_FALSE; + fgState.MouseWheelTicks = 0; + + fgState.MajorVersion = 1; + fgState.MinorVersion = 0; + fgState.ContextFlags = 0; + fgState.ContextProfile = 0; + fgState.Initialised = GL_FALSE; fgState.Position.X = -1; @@ -285,8 +491,6 @@ void fgDeinitialize( void ) fgState.GameModeDepth = 16; fgState.GameModeRefresh = 72; - fgState.Time.Set = GL_FALSE; - fgListInit( &fgState.Timers ); fgListInit( &fgState.FreeTimers ); @@ -319,6 +523,11 @@ void fgDeinitialize( void ) XCloseDisplay( fgDisplay.Display ); #elif TARGET_HOST_MS_WINDOWS + if( fgDisplay.DisplayName ) + { + free( fgDisplay.DisplayName ); + fgDisplay.DisplayName = NULL; + } /* Reset the timer granularity */ timeEndPeriod ( 1 ); @@ -524,12 +733,14 @@ void FGAPIENTRY glutInit( int* pargc, char** argv ) fgCreateStructure( ); - fgElapsedTime( ); + /* Get start time */ + fgState.Time = fgSystemTime(); /* check if GLUT_FPS env var is set */ #ifndef _WIN32_WCE { const char *fps = getenv( "GLUT_FPS" ); + if( fps ) { int interval; @@ -542,7 +753,7 @@ void FGAPIENTRY glutInit( int* pargc, char** argv ) } } - displayName = getenv( "DISPLAY"); + displayName = getenv( "DISPLAY" ); for( i = 1; i < argc; i++ ) { @@ -657,6 +868,24 @@ void FGAPIENTRY glutInit( int* pargc, char** argv ) } } +#if TARGET_HOST_MS_WINDOWS +void (__cdecl *__glutExitFunc)( int return_value ) = NULL; + +void FGAPIENTRY __glutInitWithExit( int *pargc, char **argv, void (__cdecl *exit_function)(int) ) +{ + __glutExitFunc = exit_function; + glutInit(pargc, argv); +} +#endif + +/* + * Undoes all the "glutInit" stuff + */ +void FGAPIENTRY glutExit ( void ) +{ + fgDeinitialize (); +} + /* * Sets the default initial window position for new windows */ @@ -717,19 +946,27 @@ void FGAPIENTRY glutInitDisplayString( const char* displayMode ) * delimited by blanks or tabs. */ char *token ; - int len = strlen ( displayMode ); + size_t len = strlen ( displayMode ); char *buffer = (char *)malloc ( (len+1) * sizeof(char) ); memcpy ( buffer, displayMode, len ); buffer[len] = '\0'; token = strtok ( buffer, " \t" ); + while ( token ) { /* Process this token */ int i ; + + /* Temporary fix: Ignore any length specifications and at least + * process the basic token + * TODO: Fix this permanently + */ + size_t cleanlength = strcspn ( token, "=<>~!" ); + for ( i = 0; i < NUM_TOKENS; i++ ) { - if ( strcmp ( token, Tokens[i] ) == 0 ) break ; + if ( strncmp ( token, Tokens[i], cleanlength ) == 0 ) break ; } switch ( i ) @@ -883,7 +1120,7 @@ void FGAPIENTRY glutInitDisplayString( const char* displayMode ) break ; case 36 : /* "aux": some number of aux buffers */ - glut_state_flag |= GLUT_AUX1; + glut_state_flag |= GLUT_AUX; break ; case 37 : /* Unrecognized */ @@ -901,4 +1138,46 @@ void FGAPIENTRY glutInitDisplayString( const char* displayMode ) fgState.DisplayMode = glut_state_flag; } +/* -- SETTING OPENGL 3.0 CONTEXT CREATION PARAMETERS ---------------------- */ + +void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion ) +{ + /* We will make use of these valuse when creating a new OpenGL context... */ + fgState.MajorVersion = majorVersion; + fgState.MinorVersion = minorVersion; +} + + +void FGAPIENTRY glutInitContextFlags( int flags ) +{ + /* We will make use of this value when creating a new OpenGL context... */ + fgState.ContextFlags = flags; +} + +void FGAPIENTRY glutInitContextProfile( int profile ) +{ + /* We will make use of this value when creating a new OpenGL context... */ + fgState.ContextProfile = profile; +} + +/* -------------- User Defined Error/Warning Handler Support -------------- */ + +/* + * Sets the user error handler (note the use of va_list for the args to the fmt) + */ +void FGAPIENTRY glutInitErrorFunc( void (* vfgError) ( const char *fmt, va_list ap ) ) +{ + /* This allows user programs to handle freeglut errors */ + fgState.ErrorFunc = vfgError; +} + +/* + * Sets the user warning handler (note the use of va_list for the args to the fmt) + */ +void FGAPIENTRY glutInitWarningFunc( void (* vfgWarning) ( const char *fmt, va_list ap ) ) +{ + /* This allows user programs to handle freeglut warnings */ + fgState.WarningFunc = vfgWarning; +} + /*** END OF FILE ***/