4 * The callbacks setting methods.
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7 * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8 * Creation date: Fri Dec 3 1999
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include <GL/freeglut.h>
29 #include "fg_internal.h"
31 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
37 /* Sets the global idle callback */
38 void FGAPIENTRY glutIdleFuncUcall( FGCBIdleUC callback, FGCBUserData userData )
40 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIdleFuncUcall" );
41 fgState.IdleCallback = callback;
42 fgState.IdleCallbackData = userData;
45 static void glutIdleFuncCallback( FGCBUserData userData )
47 FGCBIdle callback = (FGCBIdle)userData;
51 void FGAPIENTRY glutIdleFunc( FGCBIdle callback )
53 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIdleFunc" );
55 glutIdleFuncUcall( glutIdleFuncCallback, (FGCBUserData)callback );
57 glutIdleFuncUcall( NULL, NULL );
60 /* Creates a timer and sets its callback */
61 void FGAPIENTRY glutTimerFuncUcall( unsigned int timeOut, FGCBTimerUC callback, int timerID, FGCBUserData userData )
63 SFG_Timer *timer, *node;
65 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFuncUcall" );
67 if( (timer = fgState.FreeTimers.Last) )
69 fgListRemove( &fgState.FreeTimers, &timer->Node );
73 if( ! (timer = malloc(sizeof(SFG_Timer))) )
74 fgError( "Fatal error: "
75 "Memory allocation failure in glutTimerFunc()" );
78 timer->Callback = callback;
79 timer->CallbackData = userData;
81 timer->TriggerTime = fgElapsedTime() + timeOut;
83 /* Insert such that timers are sorted by end-time */
84 for( node = fgState.Timers.First; node; node = node->Node.Next )
86 if( node->TriggerTime > timer->TriggerTime )
90 fgListInsert( &fgState.Timers, &node->Node, &timer->Node );
93 static void glutTimerFuncCallback( int ID, FGCBUserData userData )
95 FGCBTimer callback = (FGCBTimer)userData;
99 void FGAPIENTRY glutTimerFunc( unsigned int timeOut, FGCBTimer callback, int timerID )
101 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFunc" );
103 glutTimerFuncUcall( timeOut, glutTimerFuncCallback, timerID, (FGCBUserData)callback );
105 glutTimerFuncUcall( timeOut, NULL, timerID, NULL );
108 /* Deprecated version of glutMenuStatusFunc callback setting method */
109 void FGAPIENTRY glutMenuStateFunc( FGCBMenuState callback )
111 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStateFunc" );
112 fgState.MenuStateCallback = callback;
115 /* Sets the global menu status callback for the current window */
116 void FGAPIENTRY glutMenuStatusFuncUCall( FGCBMenuStatusUC callback, FGCBUserData userData )
118 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStatusFuncUCall" );
119 fgState.MenuStatusCallback = callback;
120 fgState.MenuStatusCallbackData = userData;
123 static void glutMenuStatusFuncCallback( int menuState, int mouseX, int mouseY, FGCBUserData userData )
125 FGCBMenuStatus callback = (FGCBMenuStatus)userData;
126 callback( menuState, mouseX, mouseY );
129 void FGAPIENTRY glutMenuStatusFunc( FGCBMenuStatus callback )
131 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStatusFunc" );
133 glutMenuStatusFuncUCall( glutMenuStatusFuncCallback, (FGCBUserData)callback );
135 glutMenuStatusFuncUCall( NULL, NULL );
140 * Menu specific callbacks.
142 /* Callback upon menu destruction */
143 void FGAPIENTRY glutMenuDestroyFuncUcall( FGCBDestroyUC callback, FGCBUserData userData )
145 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFuncUcall" );
146 if( fgStructure.CurrentMenu )
148 fgStructure.CurrentMenu->Destroy = callback;
149 fgStructure.CurrentMenu->DestroyData = userData;
153 static void glutMenuDestroyFuncCallback( FGCBUserData userData )
155 FGCBDestroy callback = (FGCBDestroy)userData;
159 void FGAPIENTRY glutMenuDestroyFunc( FGCBDestroy callback )
161 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFunc" );
163 glutMenuDestroyFuncUcall( glutMenuDestroyFuncCallback, (FGCBUserData)callback );
165 glutMenuDestroyFuncUcall( NULL, NULL );
170 * All of the window-specific callbacks setting methods can be generalized to this:
172 #define SET_CALLBACK(a) \
175 if( fgStructure.CurrentWindow == NULL ) \
177 SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback, userData ); \
180 * Types need to be defined for callbacks. It's not ideal, but it works for this.
182 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b) \
183 static void glut##a##FuncCallback( FGCBUserData userData ) \
185 FGCB##b callback = (FGCB##b)userData; \
188 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,b) \
189 static void glut##a##FuncCallback( int arg1val, FGCBUserData userData ) \
191 FGCB##b callback = (FGCB##b)userData; \
192 callback( arg1val ); \
194 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b) \
195 static void glut##a##FuncCallback( int arg1val, int arg2val, FGCBUserData userData ) \
197 FGCB##b callback = (FGCB##b)userData; \
198 callback( arg1val, arg2val ); \
200 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,arg1,arg2,arg3) \
201 static void glut##a##FuncCallback( arg1 arg1val, arg2 arg2val, arg3 arg3val, FGCBUserData userData ) \
203 FGCB##b callback = (FGCB##b)userData; \
204 callback( arg1val, arg2val, arg3val ); \
206 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,b) IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,int,int,int)
207 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,b) \
208 static void glut##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, FGCBUserData userData ) \
210 FGCB##b callback = (FGCB##b)userData; \
211 callback( arg1val, arg2val, arg3val, arg4val ); \
213 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,b) \
214 static void glut##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, int arg5val, FGCBUserData userData ) \
216 FGCB##b callback = (FGCB##b)userData; \
217 callback( arg1val, arg2val, arg3val, arg4val, arg5val ); \
220 * And almost every time the callback setter function can be implemented like this:
222 #define IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,b) \
223 void FGAPIENTRY glut##a##FuncUcall( FGCB##b##UC callback, FGCBUserData userData ) \
225 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"FuncUcall" ); \
228 void FGAPIENTRY glut##a##Func( FGCB##b callback ) \
230 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"Func" ); \
232 glut##a##FuncUcall( glut##a##FuncCallback, (FGCBUserData)callback ); \
234 glut##a##FuncUcall( NULL, NULL ); \
237 * Combine _glut and _cb macros:
239 #define IMPLEMENT_CALLBACK_FUNC_ARG0(a) \
240 IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,a) \
241 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
243 #define IMPLEMENT_CALLBACK_FUNC_ARG0_2NAME(a,b) \
244 IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b) \
245 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,b)
247 #define IMPLEMENT_CALLBACK_FUNC_ARG1(a) \
248 IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,a) \
249 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
251 #define IMPLEMENT_CALLBACK_FUNC_ARG2(a) \
252 IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,a) \
253 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
255 #define IMPLEMENT_CALLBACK_FUNC_ARG2_2NAME(a,b) \
256 IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b) \
257 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,b)
259 #define IMPLEMENT_CALLBACK_FUNC_ARG3(a) \
260 IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,a) \
261 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
263 #define IMPLEMENT_CALLBACK_FUNC_ARG3_USER(a,arg1,arg2,arg3) \
264 IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,a,arg1,arg2,arg3)\
265 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
267 #define IMPLEMENT_CALLBACK_FUNC_ARG4(a) \
268 IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,a) \
269 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
271 #define IMPLEMENT_CALLBACK_FUNC_ARG5(a) \
272 IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,a) \
273 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
275 /* Implement all these callback setter functions... */
276 IMPLEMENT_CALLBACK_FUNC_ARG2(Position)
277 IMPLEMENT_CALLBACK_FUNC_ARG3_USER(Keyboard,unsigned char,int,int)
278 IMPLEMENT_CALLBACK_FUNC_ARG3_USER(KeyboardUp,unsigned char,int,int)
279 IMPLEMENT_CALLBACK_FUNC_ARG3(Special)
280 IMPLEMENT_CALLBACK_FUNC_ARG3(SpecialUp)
281 IMPLEMENT_CALLBACK_FUNC_ARG4(Mouse)
282 IMPLEMENT_CALLBACK_FUNC_ARG4(MouseWheel)
283 IMPLEMENT_CALLBACK_FUNC_ARG2(Motion)
284 IMPLEMENT_CALLBACK_FUNC_ARG2_2NAME(PassiveMotion,Passive)
285 IMPLEMENT_CALLBACK_FUNC_ARG1(Entry)
286 /* glutWMCloseFunc is an alias for glutCloseFunc; both set the window's Destroy callback */
287 IMPLEMENT_CALLBACK_FUNC_ARG0_2NAME(Close,Destroy)
288 IMPLEMENT_CALLBACK_FUNC_ARG0_2NAME(WMClose,Destroy)
289 IMPLEMENT_CALLBACK_FUNC_ARG0(OverlayDisplay)
290 IMPLEMENT_CALLBACK_FUNC_ARG1(WindowStatus)
291 IMPLEMENT_CALLBACK_FUNC_ARG2(ButtonBox)
292 IMPLEMENT_CALLBACK_FUNC_ARG2(Dials)
293 IMPLEMENT_CALLBACK_FUNC_ARG2(TabletMotion)
294 IMPLEMENT_CALLBACK_FUNC_ARG4(TabletButton)
295 IMPLEMENT_CALLBACK_FUNC_ARG2(MultiEntry)
296 IMPLEMENT_CALLBACK_FUNC_ARG5(MultiButton)
297 IMPLEMENT_CALLBACK_FUNC_ARG3(MultiMotion)
298 IMPLEMENT_CALLBACK_FUNC_ARG3(MultiPassive)
299 IMPLEMENT_CALLBACK_FUNC_ARG0(InitContext)
300 IMPLEMENT_CALLBACK_FUNC_ARG1(AppStatus)
303 * Sets the Display callback for the current window
305 void FGAPIENTRY glutDisplayFuncUcall( FGCBDisplayUC callback, FGCBUserData userData )
307 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFuncUcall" );
309 fgError( "Fatal error in program. NULL display callback not "
310 "permitted in GLUT 3.0+ or freeglut 2.0.1+" );
311 SET_CALLBACK( Display );
314 static void glutDisplayFuncCallback( FGCBUserData userData )
316 FGCBDisplay callback = (FGCBDisplay)userData;
320 void FGAPIENTRY glutDisplayFunc( FGCBDisplay callback )
322 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFunc" );
324 glutDisplayFuncUcall( glutDisplayFuncCallback, (FGCBUserData)callback );
326 glutDisplayFuncUcall( NULL, NULL );
329 void fghDefaultReshape( int width, int height, FGCBUserData userData )
331 glViewport( 0, 0, width, height );
334 void FGAPIENTRY glutReshapeFuncUcall( FGCBReshapeUC callback, FGCBUserData userData )
336 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFuncUcall" );
340 callback = fghDefaultReshape;
344 SET_CALLBACK( Reshape );
347 static void glutReshapeFuncCallback( int width, int height, FGCBUserData userData )
349 FGCBReshape callback = (FGCBReshape)userData;
350 callback( width, height );
353 void FGAPIENTRY glutReshapeFunc( FGCBReshape callback )
355 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFunc" );
357 glutReshapeFuncUcall( glutReshapeFuncCallback, (FGCBUserData)callback );
359 glutReshapeFuncUcall( NULL, NULL );
363 * Sets the Visibility callback for the current window.
364 * NB: the Visibility func is deprecated in favor of the WindowStatus func,
365 * which provides more detail. The visibility func callback is implemented
366 * as a translation step from the windowStatus func. When the user sets the
367 * windowStatus func, any visibility func is overwritten.
368 * DEVELOPER NOTE: in the library, only invoke the window status func, this
369 * gets automatically translated to the visibility func if thats what the
371 * window status is kind of anemic on win32 as there are no window messages
372 * to notify us that the window is covered by other windows or not.
373 * Should one want to query this, see
374 * http://stackoverflow.com/questions/5445889/get-which-process-window-is-actually-visible-in-c-sharp
375 * for an implementation outline (but it would be polling based, not push based).
377 static void fghVisibility( int status, FGCBUserData userData )
381 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Visibility Callback" );
382 freeglut_return_if_fail( fgStructure.CurrentWindow );
384 /* Translate window status func states to visibility states */
385 if( ( GLUT_HIDDEN == status ) || ( GLUT_FULLY_COVERED == status ) )
386 vis_status = GLUT_NOT_VISIBLE;
387 else /* GLUT_FULLY_RETAINED, GLUT_PARTIALLY_RETAINED */
388 vis_status = GLUT_VISIBLE;
390 INVOKE_WCB( *( fgStructure.CurrentWindow ), Visibility, ( vis_status ) );
393 void FGAPIENTRY glutVisibilityFuncUcall( FGCBVisibilityUC callback, FGCBUserData userData )
395 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFuncUcall" );
402 SET_CALLBACK( Visibility );
405 glutWindowStatusFuncUcall( fghVisibility, NULL );
407 glutWindowStatusFuncUcall( NULL, NULL );
410 static void glutVisibilityFuncCallback( int visibility, FGCBUserData userData )
412 FGCBVisibility callback = (FGCBVisibility)userData;
413 callback( visibility );
416 void FGAPIENTRY glutVisibilityFunc( FGCBVisibility callback )
418 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFunc" );
420 glutVisibilityFuncUcall( glutVisibilityFuncCallback, (FGCBUserData)callback );
422 glutVisibilityFuncUcall( NULL, NULL );
426 * Sets the joystick callback and polling rate for the current window
428 void FGAPIENTRY glutJoystickFuncUcall( FGCBJoystickUC callback, int pollInterval, FGCBUserData userData )
430 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFuncUcall" );
431 fgInitialiseJoysticks ();
434 fgStructure.CurrentWindow->State.JoystickPollRate <= 0 || /* Joystick callback was disabled */
435 !FETCH_WCB(*fgStructure.CurrentWindow,Joystick)
438 callback && ( pollInterval > 0 ) /* but is now enabled */
440 ++fgState.NumActiveJoysticks;
442 fgStructure.CurrentWindow->State.JoystickPollRate > 0 && /* Joystick callback was enabled */
443 FETCH_WCB(*fgStructure.CurrentWindow,Joystick)
446 !callback || ( pollInterval <= 0 ) /* but is now disabled */
448 --fgState.NumActiveJoysticks;
450 SET_CALLBACK( Joystick );
451 fgStructure.CurrentWindow->State.JoystickPollRate = pollInterval;
453 /* set last poll time such that joystick will be polled asap */
454 fgStructure.CurrentWindow->State.JoystickLastPoll = fgElapsedTime();
455 if (fgStructure.CurrentWindow->State.JoystickLastPoll < pollInterval)
456 fgStructure.CurrentWindow->State.JoystickLastPoll = 0;
458 fgStructure.CurrentWindow->State.JoystickLastPoll -= pollInterval;
461 static void glutJoystickFuncCallback( unsigned int buttons, int axis0, int axis1, int axis2, FGCBUserData userData )
463 FGCBJoystick callback = (FGCBJoystick)userData;
464 callback( buttons, axis0, axis1, axis2 );
467 void FGAPIENTRY glutJoystickFunc( FGCBJoystick callback, int pollInterval )
469 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFunc" );
471 glutJoystickFuncUcall( glutJoystickFuncCallback, pollInterval, (FGCBUserData)callback );
473 glutJoystickFuncUcall( NULL, pollInterval, NULL );
477 * Sets the spaceball motion callback for the current window
479 void FGAPIENTRY glutSpaceballMotionFuncUcall( FGCBSpaceMotionUC callback, FGCBUserData userData )
481 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFuncUcall" );
482 fgInitialiseSpaceball();
484 SET_CALLBACK( SpaceMotion );
487 static void glutSpaceballMotionFuncCallback( int x, int y, int z, FGCBUserData userData )
489 FGCBSpaceMotion callback = (FGCBSpaceMotion)userData;
493 void FGAPIENTRY glutSpaceballMotionFunc( FGCBSpaceMotion callback )
495 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFunc" );
497 glutSpaceballMotionFuncUcall( glutSpaceballMotionFuncCallback, (FGCBUserData)callback );
499 glutSpaceballMotionFuncUcall( NULL, NULL );
503 * Sets the spaceball rotate callback for the current window
505 void FGAPIENTRY glutSpaceballRotateFuncUcall( FGCBSpaceRotationUC callback, FGCBUserData userData )
507 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFuncUcall" );
508 fgInitialiseSpaceball();
510 SET_CALLBACK( SpaceRotation );
513 static void glutSpaceballRotateFuncCallback( int x, int y, int z, FGCBUserData userData )
515 FGCBSpaceRotation callback = (FGCBSpaceRotation)userData;
519 void FGAPIENTRY glutSpaceballRotateFunc( FGCBSpaceRotation callback )
521 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFunc" );
523 glutSpaceballRotateFuncUcall( glutSpaceballRotateFuncCallback, (FGCBUserData)callback );
525 glutSpaceballRotateFuncUcall( NULL, NULL );
529 * Sets the spaceball button callback for the current window
531 void FGAPIENTRY glutSpaceballButtonFuncUcall( FGCBSpaceButtonUC callback, FGCBUserData userData )
533 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFuncUcall" );
534 fgInitialiseSpaceball();
536 SET_CALLBACK( SpaceButton );
539 static void glutSpaceballButtonFuncCallback( int button, int buttonState, FGCBUserData userData )
541 FGCBSpaceButton callback = (FGCBSpaceButton)userData;
542 callback( button, buttonState );
545 void FGAPIENTRY glutSpaceballButtonFunc( FGCBSpaceButton callback )
547 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFunc" );
549 glutSpaceballButtonFuncUcall( glutSpaceballButtonFuncCallback, (FGCBUserData)callback );
551 glutSpaceballButtonFuncUcall( NULL, NULL );
554 /*** END OF FILE ***/