From 831749819dcdc1ea884c18607c2b447bbf5fca72 Mon Sep 17 00:00:00 2001 From: Rcmaniac25 Date: Fri, 30 Jun 2017 23:21:06 +0000 Subject: [PATCH] Finished implementing all user-data callbacks (GCC-only for now). Updated glutCreateMenu, glutIdleFunc, and glutTimerFunc so they handle NULL callback cases. Removed glutMenuStateFuncUcall (as glutMenuStateFunc is a depreciated function). git-svn-id: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@1809 7f0cb862-5218-0410-a997-914c9d46530a --- include/GL/freeglut_ucall.h | 9 +- src/fg_callbacks.c | 347 ++++++++++++++++++++++++++++++++++++------- src/fg_ext.c | 36 ++++- src/fg_init.c | 48 +++++- src/fg_internal.h | 242 ++++++++++++++++++++++-------- src/fg_main.c | 4 +- src/fg_menu.c | 8 +- src/fg_structure.c | 14 +- 8 files changed, 568 insertions(+), 140 deletions(-) diff --git a/include/GL/freeglut_ucall.h b/include/GL/freeglut_ucall.h index 9cbe82a..bbbd32d 100644 --- a/include/GL/freeglut_ucall.h +++ b/include/GL/freeglut_ucall.h @@ -45,7 +45,6 @@ FGAPI void FGAPIENTRY glutEntryFuncUcall( void (* callback)( int, void* ), void* FGAPI void FGAPIENTRY glutKeyboardUpFuncUcall( void (* callback)( unsigned char, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutSpecialUpFuncUcall( void (* callback)( int, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutJoystickFuncUcall( void (* callback)( unsigned int, int, int, int, void* ), int pollInterval, void* user_data ); -FGAPI void FGAPIENTRY glutMenuStateFuncUcall( void (* callback)( int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutMenuStatusFuncUcall( void (* callback)( int, int, int, void* ), void* user_data ); FGAPI void FGAPIENTRY glutOverlayDisplayFuncUcall( void (* callback)( void* ), void* user_data ); FGAPI void FGAPIENTRY glutWindowStatusFuncUcall( void (* callback)( int, void* ), void* user_data ); @@ -76,12 +75,12 @@ FGAPI void FGAPIENTRY glutMultiPassiveFuncUcall( void (* callback)( int, int, in * Initialization functions, see fg_init.c */ #include -FGAPI void FGAPIENTRY glutInitErrorFuncUcall( void (* callback)( const char *fmt, va_list ap, void* ), void* user_data ); -FGAPI void FGAPIENTRY glutInitWarningFuncUcall( void (* callback)( const char *fmt, va_list ap, void* ), void* user_data ); +FGAPI void FGAPIENTRY glutInitErrorFuncUcall( void (* callback)( const char *fmt, va_list ap, void* user_data ), void* user_data ); +FGAPI void FGAPIENTRY glutInitWarningFuncUcall( void (* callback)( const char *fmt, va_list ap, void* user_data ), void* user_data ); /* Mobile platforms lifecycle */ -FGAPI void FGAPIENTRY glutInitContextFuncUcall(void (* callback)(void*), void* user_data); -FGAPI void FGAPIENTRY glutAppStatusFuncUcall(void (* callback)(int, void*), void* user_data); +FGAPI void FGAPIENTRY glutInitContextFuncUcall( void (* callback)( void* ), void* user_data ); +FGAPI void FGAPIENTRY glutAppStatusFuncUcall( void (* callback)( int, void* ), void* user_data ); #ifdef __cplusplus } diff --git a/src/fg_callbacks.c b/src/fg_callbacks.c index b09f421..5f94b65 100644 --- a/src/fg_callbacks.c +++ b/src/fg_callbacks.c @@ -42,7 +42,7 @@ void FGAPIENTRY glutIdleFuncUcall( FGCBIdleUC callback, FGCBUserData userData ) fgState.IdleCallbackData = userData; } -void glutIdleFuncCallback( void* userData ) +static void glutIdleFuncCallback( FGCBUserData userData ) { FGCBIdle callback = (FGCBIdle)userData; callback(); @@ -51,7 +51,10 @@ void glutIdleFuncCallback( void* userData ) void FGAPIENTRY glutIdleFunc( FGCBIdle callback ) { FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIdleFunc" ); - glutIdleFuncUcall( glutIdleFuncCallback, (FGCBUserData)callback ); + if( callback ) + glutIdleFuncUcall( glutIdleFuncCallback, (FGCBUserData)callback ); + else + glutIdleFuncUcall( NULL, NULL ); } /* Creates a timer and sets its callback */ @@ -87,7 +90,7 @@ void FGAPIENTRY glutTimerFuncUcall( unsigned int timeOut, FGCBTimerUC callback, fgListInsert( &fgState.Timers, &node->Node, &timer->Node ); } -void glutTimerFuncCallback( int ID, FGCBUserData userData ) +static void glutTimerFuncCallback( int ID, FGCBUserData userData ) { FGCBTimer callback = (FGCBTimer)userData; callback( ID ); @@ -96,7 +99,10 @@ void glutTimerFuncCallback( int ID, FGCBUserData userData ) void FGAPIENTRY glutTimerFunc( unsigned int timeOut, FGCBTimer callback, int timerID ) { FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFunc" ); - glutTimerFuncUcall( timeOut, glutTimerFuncCallback, timerID, (FGCBUserData)callback ); + if( callback ) + glutTimerFuncUcall( timeOut, glutTimerFuncCallback, timerID, (FGCBUserData)callback ); + else + glutTimerFuncUcall( timeOut, NULL, timerID, NULL ); } /* Deprecated version of glutMenuStatusFunc callback setting method */ @@ -107,10 +113,26 @@ void FGAPIENTRY glutMenuStateFunc( FGCBMenuState callback ) } /* Sets the global menu status callback for the current window */ +void FGAPIENTRY glutMenuStatusFuncUCall( FGCBMenuStatusUC callback, FGCBUserData userData ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStatusFuncUCall" ); + fgState.MenuStatusCallback = callback; + fgState.MenuStatusCallbackData = userData; +} + +static void glutMenuStatusFuncCallback( int menuState, int mouseX, int mouseY, FGCBUserData userData ) +{ + FGCBMenuStatus callback = (FGCBMenuStatus)userData; + callback( menuState, mouseX, mouseY ); +} + void FGAPIENTRY glutMenuStatusFunc( FGCBMenuStatus callback ) { FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStatusFunc" ); - fgState.MenuStatusCallback = callback; + if( callback ) + glutMenuStatusFuncUCall( glutMenuStatusFuncCallback, (FGCBUserData)callback ); + else + glutMenuStatusFuncUCall( NULL, NULL ); } @@ -118,11 +140,29 @@ void FGAPIENTRY glutMenuStatusFunc( FGCBMenuStatus callback ) * Menu specific callbacks. */ /* Callback upon menu destruction */ -void FGAPIENTRY glutMenuDestroyFunc( FGCBDestroy callback ) +void FGAPIENTRY glutMenuDestroyFuncUcall( FGCBDestroyUC callback, FGCBUserData userData ) { - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFunc" ); + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFuncUcall" ); if( fgStructure.CurrentMenu ) + { fgStructure.CurrentMenu->Destroy = callback; + fgStructure.CurrentMenu->DestroyData = userData; + } +} + +static void glutMenuDestroyFuncCallback( FGCBUserData userData ) +{ + FGCBDestroy callback = (FGCBDestroy)userData; + callback(); +} + +void FGAPIENTRY glutMenuDestroyFunc( FGCBDestroy callback ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFunc" ); + if( callback ) + glutMenuDestroyFuncUcall( glutMenuDestroyFuncCallback, (FGCBUserData)callback ); + else + glutMenuDestroyFuncUcall( NULL, NULL ); } @@ -134,75 +174,191 @@ do \ { \ if( fgStructure.CurrentWindow == NULL ) \ return; \ - SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback ); \ + SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback, userData ); \ } while( 0 ) /* + * Types need to be defined for callbacks. It's not ideal, but it works for this. + */ +#define IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b) \ +static void glut##a##FuncCallback( FGCBUserData userData ) \ +{ \ + FGCB##b callback = (FGCB##b)userData; \ + callback(); \ +} +#define IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,b) \ +static void glut##a##FuncCallback( int arg1val, FGCBUserData userData ) \ +{ \ + FGCB##b callback = (FGCB##b)userData; \ + callback( arg1val ); \ +} +#define IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b) \ +static void glut##a##FuncCallback( int arg1val, int arg2val, FGCBUserData userData ) \ +{ \ + FGCB##b callback = (FGCB##b)userData; \ + callback( arg1val, arg2val ); \ +} +#define IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,arg1,arg2,arg3) \ +static void glut##a##FuncCallback( arg1 arg1val, arg2 arg2val, arg3 arg3val, FGCBUserData userData ) \ +{ \ + FGCB##b callback = (FGCB##b)userData; \ + callback( arg1val, arg2val, arg3val ); \ +} +#define IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,b) IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,int,int,int) +#define IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,b) \ +static void glut##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, FGCBUserData userData ) \ +{ \ + FGCB##b callback = (FGCB##b)userData; \ + callback( arg1val, arg2val, arg3val, arg4val ); \ +} +#define IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,b) \ +static void glut##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, int arg5val, FGCBUserData userData ) \ +{ \ + FGCB##b callback = (FGCB##b)userData; \ + callback( arg1val, arg2val, arg3val, arg4val, arg5val ); \ +} +/* * And almost every time the callback setter function can be implemented like this: */ -#define IMPLEMENT_CALLBACK_FUNC_2NAME(a,b) \ -void FGAPIENTRY glut##a##Func( FGCB##b callback ) \ +#define IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,b) \ +void FGAPIENTRY glut##a##FuncUcall( FGCB##b##UC callback, FGCBUserData userData ) \ { \ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"Func" ); \ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"FuncUcall" ); \ SET_CALLBACK( b ); \ +} \ +void FGAPIENTRY glut##a##Func( FGCB##b callback ) \ +{ \ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"Func" ); \ + if( callback ) \ + glut##a##FuncUcall( glut##a##FuncCallback, (FGCBUserData)callback ); \ + else \ + glut##a##FuncUcall( NULL, NULL ); \ } -#define IMPLEMENT_CALLBACK_FUNC(a) IMPLEMENT_CALLBACK_FUNC_2NAME(a,a) +/* + * Combine _glut and _cb macros: + */ +#define IMPLEMENT_CALLBACK_FUNC_ARG0(a) \ + IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,a) \ + IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a) -/* Implement all these callback setter functions... */ -IMPLEMENT_CALLBACK_FUNC(Position) -IMPLEMENT_CALLBACK_FUNC(Keyboard) -IMPLEMENT_CALLBACK_FUNC(KeyboardUp) -IMPLEMENT_CALLBACK_FUNC(Special) -IMPLEMENT_CALLBACK_FUNC(SpecialUp) -IMPLEMENT_CALLBACK_FUNC(Mouse) -IMPLEMENT_CALLBACK_FUNC(MouseWheel) -IMPLEMENT_CALLBACK_FUNC(Motion) -IMPLEMENT_CALLBACK_FUNC_2NAME(PassiveMotion,Passive) -IMPLEMENT_CALLBACK_FUNC(Entry) -/* glutWMCloseFunc is an alias for glutCloseFunc; both set the window's Destroy callback */ -IMPLEMENT_CALLBACK_FUNC_2NAME(Close,Destroy) -IMPLEMENT_CALLBACK_FUNC_2NAME(WMClose,Destroy) -IMPLEMENT_CALLBACK_FUNC(OverlayDisplay) -IMPLEMENT_CALLBACK_FUNC(WindowStatus) -IMPLEMENT_CALLBACK_FUNC(ButtonBox) -IMPLEMENT_CALLBACK_FUNC(Dials) -IMPLEMENT_CALLBACK_FUNC(TabletMotion) -IMPLEMENT_CALLBACK_FUNC(TabletButton) -IMPLEMENT_CALLBACK_FUNC(MultiEntry) -IMPLEMENT_CALLBACK_FUNC(MultiButton) -IMPLEMENT_CALLBACK_FUNC(MultiMotion) -IMPLEMENT_CALLBACK_FUNC(MultiPassive) -IMPLEMENT_CALLBACK_FUNC(InitContext) -IMPLEMENT_CALLBACK_FUNC(AppStatus) +#define IMPLEMENT_CALLBACK_FUNC_ARG0_2NAME(a,b) \ + IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b) \ + IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,b) + +#define IMPLEMENT_CALLBACK_FUNC_ARG1(a) \ + IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,a) \ + IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a) + +#define IMPLEMENT_CALLBACK_FUNC_ARG2(a) \ + IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,a) \ + IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a) +#define IMPLEMENT_CALLBACK_FUNC_ARG2_2NAME(a,b) \ + IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b) \ + IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,b) +#define IMPLEMENT_CALLBACK_FUNC_ARG3(a) \ + IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,a) \ + IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a) + +#define IMPLEMENT_CALLBACK_FUNC_ARG3_USER(a,arg1,arg2,arg3) \ + IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,a,arg1,arg2,arg3)\ + IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a) + +#define IMPLEMENT_CALLBACK_FUNC_ARG4(a) \ + IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,a) \ + IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a) + +#define IMPLEMENT_CALLBACK_FUNC_ARG5(a) \ + IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,a) \ + IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a) + +/* Implement all these callback setter functions... */ +IMPLEMENT_CALLBACK_FUNC_ARG2(Position) +IMPLEMENT_CALLBACK_FUNC_ARG3_USER(Keyboard,unsigned char,int,int) +IMPLEMENT_CALLBACK_FUNC_ARG3_USER(KeyboardUp,unsigned char,int,int) +IMPLEMENT_CALLBACK_FUNC_ARG3(Special) +IMPLEMENT_CALLBACK_FUNC_ARG3(SpecialUp) +IMPLEMENT_CALLBACK_FUNC_ARG4(Mouse) +IMPLEMENT_CALLBACK_FUNC_ARG4(MouseWheel) +IMPLEMENT_CALLBACK_FUNC_ARG2(Motion) +IMPLEMENT_CALLBACK_FUNC_ARG2_2NAME(PassiveMotion,Passive) +IMPLEMENT_CALLBACK_FUNC_ARG1(Entry) +/* glutWMCloseFunc is an alias for glutCloseFunc; both set the window's Destroy callback */ +IMPLEMENT_CALLBACK_FUNC_ARG0_2NAME(Close,Destroy) +IMPLEMENT_CALLBACK_FUNC_ARG0_2NAME(WMClose,Destroy) +IMPLEMENT_CALLBACK_FUNC_ARG0(OverlayDisplay) +IMPLEMENT_CALLBACK_FUNC_ARG1(WindowStatus) +IMPLEMENT_CALLBACK_FUNC_ARG2(ButtonBox) +IMPLEMENT_CALLBACK_FUNC_ARG2(Dials) +IMPLEMENT_CALLBACK_FUNC_ARG2(TabletMotion) +IMPLEMENT_CALLBACK_FUNC_ARG4(TabletButton) +IMPLEMENT_CALLBACK_FUNC_ARG2(MultiEntry) +IMPLEMENT_CALLBACK_FUNC_ARG5(MultiButton) +IMPLEMENT_CALLBACK_FUNC_ARG3(MultiMotion) +IMPLEMENT_CALLBACK_FUNC_ARG3(MultiPassive) +IMPLEMENT_CALLBACK_FUNC_ARG0(InitContext) +IMPLEMENT_CALLBACK_FUNC_ARG1(AppStatus) /* * Sets the Display callback for the current window */ -void FGAPIENTRY glutDisplayFunc( FGCBDisplay callback ) +void FGAPIENTRY glutDisplayFuncUcall( FGCBDisplayUC callback, FGCBUserData userData ) { - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFunc" ); + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFuncUcall" ); if( !callback ) fgError( "Fatal error in program. NULL display callback not " "permitted in GLUT 3.0+ or freeglut 2.0.1+" ); SET_CALLBACK( Display ); } -void fghDefaultReshape(int width, int height) +static void glutDisplayFuncCallback( FGCBUserData userData ) +{ + FGCBDisplay callback = (FGCBDisplay)userData; + callback(); +} + +void FGAPIENTRY glutDisplayFunc( FGCBDisplay callback ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFunc" ); + if( callback ) + glutDisplayFuncUcall( glutDisplayFuncCallback, (FGCBUserData)callback ); + else + glutDisplayFuncUcall( NULL, NULL ); +} + +void fghDefaultReshape( int width, int height, FGCBUserData userData ) { glViewport( 0, 0, width, height ); } -void FGAPIENTRY glutReshapeFunc( FGCBReshape callback ) +void FGAPIENTRY glutReshapeFuncUcall( FGCBReshapeUC callback, FGCBUserData userData ) { - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFunc" ); + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFuncUcall" ); if( !callback ) + { callback = fghDefaultReshape; + userData = NULL; + } SET_CALLBACK( Reshape ); } +static void glutReshapeFuncCallback( int width, int height, FGCBUserData userData ) +{ + FGCBReshape callback = (FGCBReshape)userData; + callback( width, height ); +} + +void FGAPIENTRY glutReshapeFunc( FGCBReshape callback ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFunc" ); + if( callback ) + glutReshapeFuncUcall( glutReshapeFuncCallback, (FGCBUserData)callback ); + else + glutReshapeFuncUcall( NULL, NULL ); +} + /* * Sets the Visibility callback for the current window. * NB: the Visibility func is deprecated in favor of the WindowStatus func, @@ -218,7 +374,7 @@ void FGAPIENTRY glutReshapeFunc( FGCBReshape callback ) * http://stackoverflow.com/questions/5445889/get-which-process-window-is-actually-visible-in-c-sharp * for an implementation outline (but it would be polling based, not push based). */ -static void fghVisibility( int status ) +static void fghVisibility( int status, FGCBUserData userData ) { int vis_status; @@ -234,23 +390,44 @@ static void fghVisibility( int status ) INVOKE_WCB( *( fgStructure.CurrentWindow ), Visibility, ( vis_status ) ); } -void FGAPIENTRY glutVisibilityFunc( FGCBVisibility callback ) +void FGAPIENTRY glutVisibilityFuncUcall( FGCBVisibilityUC callback, FGCBUserData userData ) { - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFunc" ); + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFuncUcall" ); + + if ( !callback ) + { + userData = NULL; + } + SET_CALLBACK( Visibility ); if( callback ) - glutWindowStatusFunc( fghVisibility ); + glutWindowStatusFuncUcall( fghVisibility, NULL ); else - glutWindowStatusFunc( NULL ); + glutWindowStatusFuncUcall( NULL, NULL ); +} + +static void glutVisibilityFuncCallback( int visibility, FGCBUserData userData ) +{ + FGCBVisibility callback = (FGCBVisibility)userData; + callback( visibility ); +} + +void FGAPIENTRY glutVisibilityFunc( FGCBVisibility callback ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFunc" ); + if( callback ) + glutVisibilityFuncUcall( glutVisibilityFuncCallback, (FGCBUserData)callback ); + else + glutVisibilityFuncUcall( NULL, NULL ); } /* * Sets the joystick callback and polling rate for the current window */ -void FGAPIENTRY glutJoystickFunc( FGCBJoystick callback, int pollInterval ) +void FGAPIENTRY glutJoystickFuncUcall( FGCBJoystickUC callback, int pollInterval, FGCBUserData userData ) { - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFunc" ); + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFuncUcall" ); fgInitialiseJoysticks (); if ( ( @@ -281,39 +458,97 @@ void FGAPIENTRY glutJoystickFunc( FGCBJoystick callback, int pollInterval ) fgStructure.CurrentWindow->State.JoystickLastPoll -= pollInterval; } +static void glutJoystickFuncCallback( unsigned int buttons, int axis0, int axis1, int axis2, FGCBUserData userData ) +{ + FGCBJoystick callback = (FGCBJoystick)userData; + callback( buttons, axis0, axis1, axis2 ); +} +void FGAPIENTRY glutJoystickFunc( FGCBJoystick callback, int pollInterval ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFunc" ); + if( callback ) + glutJoystickFuncUcall( glutJoystickFuncCallback, pollInterval, (FGCBUserData)callback ); + else + glutJoystickFuncUcall( NULL, pollInterval, NULL ); +} /* * Sets the spaceball motion callback for the current window */ -void FGAPIENTRY glutSpaceballMotionFunc( FGCBSpaceMotion callback ) +void FGAPIENTRY glutSpaceballMotionFuncUcall( FGCBSpaceMotionUC callback, FGCBUserData userData ) { - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFunc" ); + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFuncUcall" ); fgInitialiseSpaceball(); SET_CALLBACK( SpaceMotion ); } +static void glutSpaceballMotionFuncCallback( int x, int y, int z, FGCBUserData userData ) +{ + FGCBSpaceMotion callback = (FGCBSpaceMotion)userData; + callback( x, y, z ); +} + +void FGAPIENTRY glutSpaceballMotionFunc( FGCBSpaceMotion callback ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFunc" ); + if( callback ) + glutSpaceballMotionFuncUcall( glutSpaceballMotionFuncCallback, (FGCBUserData)callback ); + else + glutSpaceballMotionFuncUcall( NULL, NULL ); +} + /* * Sets the spaceball rotate callback for the current window */ -void FGAPIENTRY glutSpaceballRotateFunc( FGCBSpaceRotation callback ) +void FGAPIENTRY glutSpaceballRotateFuncUcall( FGCBSpaceRotationUC callback, FGCBUserData userData ) { - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFunc" ); + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFuncUcall" ); fgInitialiseSpaceball(); SET_CALLBACK( SpaceRotation ); } +static void glutSpaceballRotateFuncCallback( int x, int y, int z, FGCBUserData userData ) +{ + FGCBSpaceRotation callback = (FGCBSpaceRotation)userData; + callback( x, y, z ); +} + +void FGAPIENTRY glutSpaceballRotateFunc( FGCBSpaceRotation callback ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFunc" ); + if( callback ) + glutSpaceballRotateFuncUcall( glutSpaceballRotateFuncCallback, (FGCBUserData)callback ); + else + glutSpaceballRotateFuncUcall( NULL, NULL ); +} + /* * Sets the spaceball button callback for the current window */ -void FGAPIENTRY glutSpaceballButtonFunc( FGCBSpaceButton callback ) +void FGAPIENTRY glutSpaceballButtonFuncUcall( FGCBSpaceButtonUC callback, FGCBUserData userData ) { - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFunc" ); + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFuncUcall" ); fgInitialiseSpaceball(); SET_CALLBACK( SpaceButton ); } +static void glutSpaceballButtonFuncCallback( int button, int buttonState, FGCBUserData userData ) +{ + FGCBSpaceButton callback = (FGCBSpaceButton)userData; + callback( button, buttonState ); +} + +void FGAPIENTRY glutSpaceballButtonFunc( FGCBSpaceButton callback ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFunc" ); + if( callback ) + glutSpaceballButtonFuncUcall( glutSpaceballButtonFuncCallback, (FGCBUserData)callback ); + else + glutSpaceballButtonFuncUcall( NULL, NULL ); +} + /*** END OF FILE ***/ diff --git a/src/fg_ext.c b/src/fg_ext.c index 4c1f9c9..0ddb560 100644 --- a/src/fg_ext.c +++ b/src/fg_ext.c @@ -215,7 +215,41 @@ static GLUTproc fghGetGLUTProcAddress( const char* procName ) CHECK_NAME(glutCreateMenuUcall); CHECK_NAME(glutTimerFuncUcall); CHECK_NAME(glutIdleFuncUcall); - //TODO + CHECK_NAME(glutKeyboardFuncUcall); + CHECK_NAME(glutSpecialFuncUcall); + CHECK_NAME(glutReshapeFuncUcall); + CHECK_NAME(glutVisibilityFuncUcall); + CHECK_NAME(glutDisplayFuncUcall); + CHECK_NAME(glutMouseFuncUcall); + CHECK_NAME(glutMotionFuncUcall); + CHECK_NAME(glutPassiveMotionFuncUcall); + CHECK_NAME(glutEntryFuncUcall); + CHECK_NAME(glutKeyboardUpFuncUcall); + CHECK_NAME(glutSpecialUpFuncUcall); + CHECK_NAME(glutJoystickFuncUcall); + CHECK_NAME(glutMenuStatusFuncUcall); + CHECK_NAME(glutOverlayDisplayFuncUcall); + CHECK_NAME(glutWindowStatusFuncUcall); + CHECK_NAME(glutSpaceballMotionFuncUcall); + CHECK_NAME(glutSpaceballRotateFuncUcall); + CHECK_NAME(glutSpaceballButtonFuncUcall); + CHECK_NAME(glutButtonBoxFuncUcall); + CHECK_NAME(glutDialsFuncUcall); + CHECK_NAME(glutTabletMotionFuncUcall); + CHECK_NAME(glutTabletButtonFuncUcall); + CHECK_NAME(glutMouseWheelFuncUcall); + CHECK_NAME(glutPositionFuncUcall); + CHECK_NAME(glutCloseFuncUcall); + CHECK_NAME(glutWMCloseFuncUcall); + CHECK_NAME(glutMenuDestroyFuncUcall); + CHECK_NAME(glutMultiEntryFuncUcall); + CHECK_NAME(glutMultiButtonFuncUcall); + CHECK_NAME(glutMultiMotionFuncUcall); + CHECK_NAME(glutMultiPassiveFuncUcall); + CHECK_NAME(glutInitErrorFuncUcall); + CHECK_NAME(glutInitWarningFuncUcall); + CHECK_NAME(glutInitContextFuncUcall); + CHECK_NAME(glutAppStatusFuncUcall); #undef CHECK_NAME return NULL; diff --git a/src/fg_init.c b/src/fg_init.c index ffd3f99..a408bbe 100644 --- a/src/fg_init.c +++ b/src/fg_init.c @@ -74,6 +74,7 @@ SFG_State fgState = { { -1, -1, GL_FALSE }, /* Position */ 0, /* ActiveMenus */ NULL, /* MenuStateCallback */ NULL, /* MenuStatusCallback */ + NULL, /* MenuStatusCallbackData */ FREEGLUT_MENU_FONT, { -1, -1, GL_TRUE }, /* GameModeSize */ -1, /* GameModeDepth */ @@ -96,7 +97,9 @@ SFG_State fgState = { { -1, -1, GL_FALSE }, /* Position */ 0, /* OpenGL ContextProfile */ 0, /* HasOpenGL20 */ NULL, /* ErrorFunc */ - NULL /* WarningFunc */ + NULL, /* ErrorFuncData */ + NULL, /* WarningFunc */ + NULL /* WarningFuncData */ }; @@ -299,10 +302,11 @@ void fgDeinitialize( void ) fgListInit( &fgState.Timers ); fgListInit( &fgState.FreeTimers ); - fgState.IdleCallback = NULL; - fgState.IdleCallbackData = NULL; - fgState.MenuStateCallback = ( FGCBMenuState )NULL; - fgState.MenuStatusCallback = ( FGCBMenuStatus )NULL; + fgState.IdleCallback = ( FGCBIdleUC )NULL; + fgState.IdleCallbackData = NULL; + fgState.MenuStateCallback = ( FGCBMenuState )NULL; + fgState.MenuStatusCallback = ( FGCBMenuStatusUC )NULL; + fgState.MenuStatusCallbackData = NULL; fgState.SwapCount = 0; fgState.SwapTime = 0; @@ -670,19 +674,49 @@ void FGAPIENTRY glutInitContextProfile( int profile ) /* * Sets the user error handler (note the use of va_list for the args to the fmt) */ -void FGAPIENTRY glutInitErrorFunc( FGError callback ) +void FGAPIENTRY glutInitErrorFuncUcall( FGErrorUC callback, FGCBUserData userData ) { /* This allows user programs to handle freeglut errors */ fgState.ErrorFunc = callback; + fgState.ErrorFuncData = userData; +} + +static void glutInitErrorFuncCallback( const char *fmt, va_list ap, FGCBUserData userData ) +{ + FGError callback = (FGError)userData; + callback( fmt, ap ); +} + +void FGAPIENTRY glutInitErrorFunc( FGError callback ) +{ + if (callback) + glutInitErrorFuncUcall( glutInitErrorFuncCallback, (FGCBUserData)callback ); + else + glutInitErrorFuncUcall( NULL, NULL ); } /* * Sets the user warning handler (note the use of va_list for the args to the fmt) */ -void FGAPIENTRY glutInitWarningFunc( FGWarning callback ) +void FGAPIENTRY glutInitWarningFuncUcall( FGWarningUC callback, FGCBUserData userData ) { /* This allows user programs to handle freeglut warnings */ fgState.WarningFunc = callback; + fgState.WarningFuncData = userData; +} + +static void glutInitWarningFuncCallback( const char *fmt, va_list ap, FGCBUserData userData ) +{ + FGWarning callback = (FGWarning)userData; + callback( fmt, ap ); +} + +void FGAPIENTRY glutInitWarningFunc( FGWarning callback ) +{ + if (callback) + glutInitWarningFuncUcall( glutInitWarningFuncCallback, (FGCBUserData)callback ); + else + glutInitWarningFuncUcall( NULL, NULL ); } /*** END OF FILE ***/ diff --git a/src/fg_internal.h b/src/fg_internal.h index 8e27f54..69401d0 100644 --- a/src/fg_internal.h +++ b/src/fg_internal.h @@ -218,54 +218,87 @@ /* Freeglut callbacks type definitions */ typedef void* FGCBUserData; -typedef void (* FGCBDisplay )( void ); -typedef void (* FGCBReshape )( int, int ); -typedef void (* FGCBPosition )( int, int ); -typedef void (* FGCBVisibility )( int ); -typedef void (* FGCBKeyboard )( unsigned char, int, int ); -typedef void (* FGCBKeyboardUp )( unsigned char, int, int ); -typedef void (* FGCBSpecial )( int, int, int ); -typedef void (* FGCBSpecialUp )( int, int, int ); -typedef void (* FGCBMouse )( int, int, int, int ); -typedef void (* FGCBMouseWheel )( int, int, int, int ); -typedef void (* FGCBMotion )( int, int ); -typedef void (* FGCBPassive )( int, int ); -typedef void (* FGCBEntry )( int ); -typedef void (* FGCBWindowStatus )( int ); -typedef void (* FGCBJoystick )( unsigned int, int, int, int ); -typedef void (* FGCBOverlayDisplay)( void ); -typedef void (* FGCBSpaceMotion )( int, int, int ); -typedef void (* FGCBSpaceRotation )( int, int, int ); -typedef void (* FGCBSpaceButton )( int, int ); -typedef void (* FGCBDials )( int, int ); -typedef void (* FGCBButtonBox )( int, int ); -typedef void (* FGCBTabletMotion )( int, int ); -typedef void (* FGCBTabletButton )( int, int, int, int ); -typedef void (* FGCBDestroy )( void ); /* Used for both window and menu destroy callbacks */ - -typedef void (* FGCBMultiEntry )( int, int ); -typedef void (* FGCBMultiButton )( int, int, int, int, int ); -typedef void (* FGCBMultiMotion )( int, int, int ); -typedef void (* FGCBMultiPassive )( int, int, int ); - -typedef void (* FGCBInitContext)(); -typedef void (* FGCBAppStatus)(int); +typedef void (* FGCBDisplay )( void ); +typedef void (* FGCBDisplayUC )( FGCBUserData ); +typedef void (* FGCBReshape )( int, int ); +typedef void (* FGCBReshapeUC )( int, int, FGCBUserData ); +typedef void (* FGCBPosition )( int, int ); +typedef void (* FGCBPositionUC )( int, int, FGCBUserData ); +typedef void (* FGCBVisibility )( int ); +typedef void (* FGCBVisibilityUC )( int, FGCBUserData ); +typedef void (* FGCBKeyboard )( unsigned char, int, int ); +typedef void (* FGCBKeyboardUC )( unsigned char, int, int, FGCBUserData ); +typedef void (* FGCBKeyboardUp )( unsigned char, int, int ); +typedef void (* FGCBKeyboardUpUC )( unsigned char, int, int, FGCBUserData ); +typedef void (* FGCBSpecial )( int, int, int ); +typedef void (* FGCBSpecialUC )( int, int, int, FGCBUserData ); +typedef void (* FGCBSpecialUp )( int, int, int ); +typedef void (* FGCBSpecialUpUC )( int, int, int, FGCBUserData ); +typedef void (* FGCBMouse )( int, int, int, int ); +typedef void (* FGCBMouseUC )( int, int, int, int, FGCBUserData ); +typedef void (* FGCBMouseWheel )( int, int, int, int ); +typedef void (* FGCBMouseWheelUC )( int, int, int, int, FGCBUserData ); +typedef void (* FGCBMotion )( int, int ); +typedef void (* FGCBMotionUC )( int, int, FGCBUserData ); +typedef void (* FGCBPassive )( int, int ); +typedef void (* FGCBPassiveUC )( int, int, FGCBUserData ); +typedef void (* FGCBEntry )( int ); +typedef void (* FGCBEntryUC )( int, FGCBUserData ); +typedef void (* FGCBWindowStatus )( int ); +typedef void (* FGCBWindowStatusUC )( int, FGCBUserData ); +typedef void (* FGCBJoystick )( unsigned int, int, int, int ); +typedef void (* FGCBJoystickUC )( unsigned int, int, int, int, FGCBUserData ); +typedef void (* FGCBOverlayDisplay )( void ); +typedef void (* FGCBOverlayDisplayUC)( FGCBUserData ); +typedef void (* FGCBSpaceMotion )( int, int, int ); +typedef void (* FGCBSpaceMotionUC )( int, int, int, FGCBUserData ); +typedef void (* FGCBSpaceRotation )( int, int, int ); +typedef void (* FGCBSpaceRotationUC )( int, int, int, FGCBUserData ); +typedef void (* FGCBSpaceButton )( int, int ); +typedef void (* FGCBSpaceButtonUC )( int, int, FGCBUserData ); +typedef void (* FGCBDials )( int, int ); +typedef void (* FGCBDialsUC )( int, int, FGCBUserData ); +typedef void (* FGCBButtonBox )( int, int ); +typedef void (* FGCBButtonBoxUC )( int, int, FGCBUserData ); +typedef void (* FGCBTabletMotion )( int, int ); +typedef void (* FGCBTabletMotionUC )( int, int, FGCBUserData ); +typedef void (* FGCBTabletButton )( int, int, int, int ); +typedef void (* FGCBTabletButtonUC )( int, int, int, int, FGCBUserData ); +typedef void (* FGCBDestroy )( void ); /* Used for both window and menu destroy callbacks */ +typedef void (* FGCBDestroyUC )( FGCBUserData ); + +typedef void (* FGCBMultiEntry )( int, int ); +typedef void (* FGCBMultiEntryUC )( int, int, FGCBUserData ); +typedef void (* FGCBMultiButton )( int, int, int, int, int ); +typedef void (* FGCBMultiButtonUC )( int, int, int, int, int, FGCBUserData ); +typedef void (* FGCBMultiMotion )( int, int, int ); +typedef void (* FGCBMultiMotionUC )( int, int, int, FGCBUserData ); +typedef void (* FGCBMultiPassive )( int, int, int ); +typedef void (* FGCBMultiPassiveUC )( int, int, int, FGCBUserData ); + +typedef void (* FGCBInitContext )( void ); +typedef void (* FGCBInitContextUC )( FGCBUserData ); +typedef void (* FGCBAppStatus )( int ); +typedef void (* FGCBAppStatusUC )( int, FGCBUserData ); /* The global callbacks type definitions */ -typedef void (* FGCBIdle )( void ); -typedef void (* FGCBIdleUC )( FGCBUserData ); -typedef void (* FGCBTimer )( int ); -typedef void (* FGCBTimerUC )( int, FGCBUserData ); -typedef void (* FGCBMenuState )( int ); -typedef void (* FGCBMenuStatus )( int, int, int ); +typedef void (* FGCBIdle )( void ); \ +typedef void (* FGCBIdleUC )( FGCBUserData ); +typedef void (* FGCBTimer )( int ); +typedef void (* FGCBTimerUC )( int, FGCBUserData ); +typedef void (* FGCBMenuState )( int ); +typedef void (* FGCBMenuStatus )( int, int, int ); +typedef void (* FGCBMenuStatusUC )( int, int, int, FGCBUserData ); /* The callback used when creating/using menus */ -typedef void (* FGCBMenu )( int ); -typedef void (* FGCBMenuUC )( int, FGCBUserData ); +typedef void (* FGCBMenu )( int ); +typedef void (* FGCBMenuUC )( int, FGCBUserData ); /* The FreeGLUT error/warning handler type definition */ -typedef void (* FGError ) ( const char *fmt, va_list ap); -typedef void (* FGWarning ) ( const char *fmt, va_list ap); +typedef void (* FGError )( const char *fmt, va_list ap ); +typedef void (* FGErrorUC )( const char *fmt, va_list ap, FGCBUserData userData ); +typedef void (* FGWarning )( const char *fmt, va_list ap ); +typedef void (* FGWarningUC )( const char *fmt, va_list ap, FGCBUserData userData ); /* A list structure */ @@ -337,24 +370,25 @@ struct tagSFG_State int ActiveMenus; /* Num. of currently active menus */ FGCBMenuState MenuStateCallback; /* Menu callbacks are global */ - FGCBMenuStatus MenuStatusCallback; + FGCBMenuStatusUC MenuStatusCallback; + FGCBUserData MenuStatusCallbackData; void* MenuFont; /* Font to be used for newly created menus */ SFG_XYUse GameModeSize; /* Game mode screen's dimensions */ int GameModeDepth; /* The pixel depth for game mode */ int GameModeRefresh; /* The refresh rate for game mode */ - int ActionOnWindowClose; /* Action when user closes window */ + int ActionOnWindowClose; /* Action when user closes window */ - fgExecutionState ExecState; /* Used for GLUT termination */ - char *ProgramName; /* Name of the invoking program */ - GLboolean JoysticksInitialised; /* Only initialize if application calls for them */ - int NumActiveJoysticks; /* Number of active joysticks (callback defined and positive pollrate) -- if zero, don't poll joysticks */ - GLboolean InputDevsInitialised; /* Only initialize if application calls for them */ + fgExecutionState ExecState; /* Used for GLUT termination */ + char *ProgramName; /* Name of the invoking program */ + GLboolean JoysticksInitialised; /* Only initialize if application calls for them */ + int NumActiveJoysticks; /* Number of active joysticks (callback defined and positive pollrate) -- if zero, don't poll joysticks */ + GLboolean InputDevsInitialised; /* Only initialize if application calls for them */ int MouseWheelTicks; /* Number of ticks the mouse wheel has turned */ - int AuxiliaryBufferNumber; /* Number of auxiliary buffers */ + int AuxiliaryBufferNumber;/* Number of auxiliary buffers */ int SampleNumber; /* Number of samples per pixel */ GLboolean SkipStaleMotion; /* skip stale motion events */ @@ -367,8 +401,10 @@ struct tagSFG_State int ContextFlags; /* OpenGL context flags */ int ContextProfile; /* OpenGL context profile */ int HasOpenGL20; /* fgInitGL2 could find all OpenGL 2.0 functions */ - FGError ErrorFunc; /* User defined error handler */ - FGWarning WarningFunc; /* User defined warning handler */ + FGErrorUC ErrorFunc; /* User defined error handler */ + FGCBUserData ErrorFuncData; /* User defined error handler user data */ + FGWarningUC WarningFunc; /* User defined warning handler */ + FGCBUserData WarningFuncData; /* User defined warning handler user data */ }; /* The structure used by display initialization in fg_init.c */ @@ -518,11 +554,12 @@ typedef void (*SFG_Proc)(); /* * SET_WCB() is used as: * - * SET_WCB( window, cbname, func ); + * SET_WCB( window, cbname, func, udata ); * * ...where {window} is the freeglut window to set the callback, * {cbname} is the window-specific callback to set, - * {func} is a function-pointer. + * {func} is a function-pointer, + * {udata} is a void* pointer for user data. * * Originally, {FETCH_WCB( ... ) = func} was rather sloppily used, * but this can cause warnings because the FETCH_WCB() macro type- @@ -532,11 +569,14 @@ typedef void (*SFG_Proc)(); * and for no other reason. Since it's hidden in the macro, the * ugliness is felt to be rather benign. */ -#define SET_WCB(window,cbname,func) \ +#define SET_WCB(window,cbname,func,udata) \ do \ { \ if( FETCH_WCB( window, cbname ) != (SFG_Proc)(func) ) \ + { \ (((window).CallBacks[WCB_ ## cbname]) = (SFG_Proc)(func)); \ + (((window).CallbackDatas[WCB_ ## cbname]) = (udata)); \ + } \ } while( 0 ) /* @@ -554,6 +594,82 @@ do \ ((window).CallBacks[WCB_ ## cbname]) /* + * FETCH_USER_DATA_WCB() is used as: + * + * FETCH_USER_DATA_WCB( window, cbname ); + * + * ...where {window} is the freeglut window, + * {cbname} is the window-specific callback to be invoked, + * + * This expects a variable named "window" of type tagSFG_Window to exist. + */ +/* + * FETCH_USER_DATA_WCB() is used as: + * + * FETCH_USER_DATA_WCB( window, cbname ); + * + * ...where {window} is the freeglut window to fetch the callback data from, + * {cbname} is the window-specific callback data to fetch. + * + * The result is the callback data pointer. + */ +#define FETCH_USER_DATA_WCB(window,cbname) \ + ((window).CallbackDatas[WCB_ ## cbname]) + +/* + * EXPAND_WCB() is used as: + * + * EXPAND_WCB arg_list + * + * ... where {(arg_list)} is the parameter list. + * + * This will take the arg_list and extend it by one argument, adding + * the argument "userData" to the end of the list. + * + * All additional args are to get around trailing ',', argument counts, + * and not needing a GCC extension to make this work. + * + * Minor modification of: + * http://stackoverflow.com/questions/5355241/generating-function-declaration-using-a-macro-iteration/5355946#5355946 + * + * Supports up to five arguments + */ +#if TARGET_HOST_MS_WINDOWS + +/* FIXME: Does VC6 support variadic macros? I don't think so (variadic macros came with C99. VC6 came out in 1998) */ + +/* FIXME: VC++ has a greedy preprocessor. + * The preprocessor resolves the macros on use instead of after on argument completion/token usage. + * e.g.: PP_HAS_ARGS_IMPL2(ONE_OR_MORE, ...) -> PP_HAS_ARGS_IMPL2(, ...) -> "Error, not enough tokens for PP_HAS_ARGS_IMPL2" + */ +#define EXPAND_WCB(...) (__VA_ARGS__) + +#else // #if TARGET_HOST_MS_WINDOWS + +#define PP_HAS_ARGS_IMPL2(_0, _1, _2, _3, _4, _5, N, ...) N +#define PP_HAS_ARGS_SOURCE() \ + ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ZERO + +#define PP_HAS_ARGS_IMPL(...) \ + PP_HAS_ARGS_IMPL2(__VA_ARGS__) +#define PP_HAS_ARGS(...) \ + PP_HAS_ARGS_IMPL(NOT_EXIST, ##__VA_ARGS__, PP_HAS_ARGS_SOURCE()) + +#define EXPAND_WCB_ZERO(x) \ + (userData) +#define EXPAND_WCB_ONE_OR_MORE(...) \ + (__VA_ARGS__, userData) + +#define EXPAND_WCB_DISAMBIGUATE2(has_args, ...) \ + EXPAND_WCB_ ## has_args (__VA_ARGS__) +#define EXPAND_WCB_DISAMBIGUATE(has_args, ...) \ + EXPAND_WCB_DISAMBIGUATE2(has_args, __VA_ARGS__) +#define EXPAND_WCB(...) \ + EXPAND_WCB_DISAMBIGUATE(PP_HAS_ARGS(__VA_ARGS__), __VA_ARGS__) + +#endif // #if TARGET_HOST_MS_WINDOWS + +/* * INVOKE_WCB() is used as: * * INVOKE_WCB( window, cbname, ( arg_list ) ); @@ -578,9 +694,10 @@ do \ { \ if( FETCH_WCB( window, cbname ) ) \ { \ - FGCB ## cbname func = (FGCB ## cbname)(FETCH_WCB( window, cbname )); \ + FGCB ## cbname ## UC func = (FGCB ## cbname ## UC)(FETCH_WCB( window, cbname )); \ + FGCBUserData userData = FETCH_USER_DATA_WCB( window, cbname ); \ fgSetWindow( &window ); \ - func arg_list; \ + func EXPAND_WCB arg_list; \ } \ } while( 0 ) #else @@ -590,7 +707,8 @@ do \ if( FETCH_WCB( window, cbname ) ) \ { \ fgSetWindow( &window ); \ - ((FGCB ## cbname)FETCH_WCB( window, cbname )) arg_list; \ + FGCBUserData userData = FETCH_USER_DATA_WCB( window, cbname ); \ + ((FGCB ## cbname ## UC)FETCH_WCB( window, cbname )) EXPAND_WCB arg_list; \ } \ } while( 0 ) #endif @@ -671,7 +789,8 @@ struct tagSFG_Menu SFG_List Entries; /* The menu entries list */ FGCBMenuUC Callback; /* The menu callback */ FGCBUserData CallbackData; /* The menu callback user data */ - FGCBDestroy Destroy; /* Destruction callback */ + FGCBDestroyUC Destroy; /* Destruction callback */ + FGCBUserData DestroyData; /* Destruction callback user data */ GLboolean IsActive; /* Is the menu selected? */ void* Font; /* Font to be used for displaying this menu */ int Width; /* Menu box width in pixels */ @@ -709,10 +828,11 @@ struct tagSFG_Window SFG_Context Window; /* Window and OpenGL context */ SFG_WindowState State; /* The window state */ SFG_Proc CallBacks[ TOTAL_CALLBACKS ]; /* Array of window callbacks */ + FGCBUserData CallbackDatas[ TOTAL_CALLBACKS ]; /* Array of window callback datas */ void *UserData ; /* For use by user */ - SFG_Menu* Menu[ FREEGLUT_MAX_MENUS ]; /* Menus appended to window */ - SFG_Menu* ActiveMenu; /* The window's active menu */ + SFG_Menu* Menu[ FREEGLUT_MAX_MENUS ]; /* Menus appended to window */ + SFG_Menu* ActiveMenu; /* The window's active menu */ SFG_Window* Parent; /* The parent to this window */ SFG_List Children; /* The subwindows d.l. list */ diff --git a/src/fg_main.c b/src/fg_main.c index 6e9ff48..45f13f5 100644 --- a/src/fg_main.c +++ b/src/fg_main.c @@ -269,7 +269,7 @@ void fgError( const char *fmt, ... ) va_start( ap, fmt ); /* call user set error handler here */ - fgState.ErrorFunc(fmt, ap); + fgState.ErrorFunc(fmt, ap, fgState.ErrorFuncData); va_end( ap ); @@ -302,7 +302,7 @@ void fgWarning( const char *fmt, ... ) va_start( ap, fmt ); /* call user set warning handler here */ - fgState.WarningFunc(fmt, ap); + fgState.WarningFunc(fmt, ap, fgState.WarningFuncData); va_end( ap ); diff --git a/src/fg_menu.c b/src/fg_menu.c index cad5b83..1b07b1a 100644 --- a/src/fg_menu.c +++ b/src/fg_menu.c @@ -531,7 +531,7 @@ static void fghActivateMenu( SFG_Window* window, int button ) fgState.MenuStateCallback(GLUT_MENU_IN_USE); if (fgState.MenuStatusCallback) /* window->State.MouseX and window->State.MouseY are relative to client area origin, as needed */ - fgState.MenuStatusCallback(GLUT_MENU_IN_USE, window->State.MouseX, window->State.MouseY); + fgState.MenuStatusCallback(GLUT_MENU_IN_USE, window->State.MouseX, window->State.MouseY, fgState.MenuStatusCallbackData); } fgSetWindow( menu->Window ); @@ -725,7 +725,7 @@ void fgDeactivateMenu( SFG_Window *window ) SFG_XYUse mouse_pos; fghPlatformGetCursorPos(parent_window, GL_TRUE, &mouse_pos); - fgState.MenuStatusCallback(GLUT_MENU_NOT_IN_USE, mouse_pos.X, mouse_pos.Y); + fgState.MenuStatusCallback(GLUT_MENU_NOT_IN_USE, mouse_pos.X, mouse_pos.Y, fgState.MenuStatusCallbackData); } } } @@ -791,7 +791,7 @@ int FGAPIENTRY glutCreateMenuUcall( FGCBMenuUC callback, FGCBUserData userData ) } /* Standard glutCreateMenu */ -void glutCreateMenuCallback( int menu, FGCBUserData userData ) +static void glutCreateMenuCallback( int menu, FGCBUserData userData ) { FGCBMenu callback = (FGCBMenu)userData; callback( menu ); @@ -800,6 +800,8 @@ void glutCreateMenuCallback( int menu, FGCBUserData userData ) int FGAPIENTRY glutCreateMenu( FGCBMenu callback ) { FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateMenu" ); + if (!callback) + return glutCreateMenuUcall( NULL, NULL ); return glutCreateMenuUcall( glutCreateMenuCallback, (FGCBUserData)callback ); } diff --git a/src/fg_structure.c b/src/fg_structure.c index c279b4a..4274667 100644 --- a/src/fg_structure.c +++ b/src/fg_structure.c @@ -49,7 +49,7 @@ SFG_Structure fgStructure = { { NULL, NULL }, /* The list of windows */ /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ extern void fgPlatformCreateWindow ( SFG_Window *window ); -extern void fghDefaultReshape(int width, int height); +extern void fghDefaultReshape(int width, int height, FGCBUserData userData); static void fghClearCallBacks( SFG_Window *window ) { @@ -57,7 +57,10 @@ static void fghClearCallBacks( SFG_Window *window ) { int i; for( i = 0; i < TOTAL_CALLBACKS; ++i ) + { window->CallBacks[ i ] = NULL; + window->CallbackDatas[ i ] = NULL; + } } } @@ -83,7 +86,7 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title, fgPlatformCreateWindow ( window ); fghClearCallBacks( window ); - SET_WCB( *window, Reshape, fghDefaultReshape); + SET_WCB( *window, Reshape, fghDefaultReshape, NULL); /* Initialize the object properties */ window->ID = ++fgStructure.WindowID; @@ -174,9 +177,10 @@ void fgAddToWindowDestroyList( SFG_Window* window ) * to ensure that they are no longer called after this point. */ { - FGCBDestroy destroy = (FGCBDestroy)FETCH_WCB( *window, Destroy ); + FGCBDestroyUC destroy = (FGCBDestroyUC)FETCH_WCB( *window, Destroy ); + FGCBUserData destroyData = FETCH_USER_DATA_WCB( *window, Destroy ); fghClearCallBacks( window ); - SET_WCB( *window, Destroy, destroy ); + SET_WCB( *window, Destroy, destroy, destroyData ); } } @@ -303,7 +307,7 @@ void fgDestroyMenu( SFG_Menu* menu ) { SFG_Menu *activeMenu=fgStructure.CurrentMenu; fgStructure.CurrentMenu = menu; - menu->Destroy( ); + menu->Destroy( menu->DestroyData ); fgStructure.CurrentMenu = activeMenu; } -- 1.7.10.4