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 fghIdleFuncCallback( FGCBUserData userData )
47 FGCBIdle callback = (FGCBIdle)userData;
51 void FGAPIENTRY glutIdleFunc( FGCBIdle callback )
53 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIdleFunc" );
55 glutIdleFuncUcall( fghIdleFuncCallback, (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 fghTimerFuncCallback( 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, fghTimerFuncCallback, 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 fghMenuStatusFuncCallback( 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( fghMenuStatusFuncCallback, (FGCBUserData)callback );
135 glutMenuStatusFuncUcall( NULL, NULL );
139 * Menu specific callbacks.
141 /* Callback upon menu destruction */
142 void FGAPIENTRY glutMenuDestroyFuncUcall( FGCBDestroyUC callback, FGCBUserData userData )
144 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFuncUcall" );
145 if( fgStructure.CurrentMenu )
147 fgStructure.CurrentMenu->Destroy = callback;
148 fgStructure.CurrentMenu->DestroyData = userData;
152 static void fghMenuDestroyFuncCallback( FGCBUserData userData )
154 FGCBDestroy callback = (FGCBDestroy)userData;
158 void FGAPIENTRY glutMenuDestroyFunc( FGCBDestroy callback )
160 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFunc" );
162 glutMenuDestroyFuncUcall( fghMenuDestroyFuncCallback, (FGCBUserData)callback );
164 glutMenuDestroyFuncUcall( NULL, NULL );
169 * All of the window-specific callbacks setting methods can be generalized to this:
171 #define SET_CALLBACK(a) \
174 if( fgStructure.CurrentWindow == NULL ) \
176 SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback, userData ); \
179 * Types need to be defined for callbacks. It's not ideal, but it works for this.
181 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b) \
182 static void fgh##a##FuncCallback( FGCBUserData userData ) \
184 FGCB##b callback = (FGCB##b)userData; \
187 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,b) \
188 static void fgh##a##FuncCallback( int arg1val, FGCBUserData userData ) \
190 FGCB##b callback = (FGCB##b)userData; \
191 callback( arg1val ); \
193 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b) \
194 static void fgh##a##FuncCallback( int arg1val, int arg2val, FGCBUserData userData ) \
196 FGCB##b callback = (FGCB##b)userData; \
197 callback( arg1val, arg2val ); \
199 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,arg1,arg2,arg3) \
200 static void fgh##a##FuncCallback( arg1 arg1val, arg2 arg2val, arg3 arg3val, FGCBUserData userData ) \
202 FGCB##b callback = (FGCB##b)userData; \
203 callback( arg1val, arg2val, arg3val ); \
205 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,b) IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,int,int,int)
206 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,b) \
207 static void fgh##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, FGCBUserData userData ) \
209 FGCB##b callback = (FGCB##b)userData; \
210 callback( arg1val, arg2val, arg3val, arg4val ); \
212 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,b) \
213 static void fgh##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, int arg5val, FGCBUserData userData ) \
215 FGCB##b callback = (FGCB##b)userData; \
216 callback( arg1val, arg2val, arg3val, arg4val, arg5val ); \
219 * And almost every time the callback setter function can be implemented like this:
221 #define IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,b) \
222 void FGAPIENTRY glut##a##FuncUcall( FGCB##b##UC callback, FGCBUserData userData ) \
224 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"FuncUcall" ); \
227 void FGAPIENTRY glut##a##Func( FGCB##b callback ) \
229 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"Func" ); \
231 glut##a##FuncUcall( fgh##a##FuncCallback, (FGCBUserData)callback ); \
233 glut##a##FuncUcall( NULL, NULL ); \
236 * Combine _glut and _cb macros:
238 #define IMPLEMENT_CALLBACK_FUNC_ARG0(a) \
239 IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,a) \
240 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
242 #define IMPLEMENT_CALLBACK_FUNC_ARG0_2NAME(a,b) \
243 IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b) \
244 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,b)
246 #define IMPLEMENT_CALLBACK_FUNC_ARG1(a) \
247 IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,a) \
248 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
250 #define IMPLEMENT_CALLBACK_FUNC_ARG2(a) \
251 IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,a) \
252 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
254 #define IMPLEMENT_CALLBACK_FUNC_ARG2_2NAME(a,b) \
255 IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b) \
256 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,b)
258 #define IMPLEMENT_CALLBACK_FUNC_ARG3(a) \
259 IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,a) \
260 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
262 #define IMPLEMENT_CALLBACK_FUNC_ARG3_USER(a,arg1,arg2,arg3) \
263 IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,a,arg1,arg2,arg3)\
264 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
266 #define IMPLEMENT_CALLBACK_FUNC_ARG4(a) \
267 IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,a) \
268 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
270 #define IMPLEMENT_CALLBACK_FUNC_ARG5(a) \
271 IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,a) \
272 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
274 /* Implement all these callback setter functions... */
275 IMPLEMENT_CALLBACK_FUNC_ARG2(Position)
276 IMPLEMENT_CALLBACK_FUNC_ARG3_USER(Keyboard,unsigned char,int,int)
277 IMPLEMENT_CALLBACK_FUNC_ARG3_USER(KeyboardUp,unsigned char,int,int)
278 IMPLEMENT_CALLBACK_FUNC_ARG3(Special)
279 IMPLEMENT_CALLBACK_FUNC_ARG3(SpecialUp)
280 IMPLEMENT_CALLBACK_FUNC_ARG4(Mouse)
281 IMPLEMENT_CALLBACK_FUNC_ARG4(MouseWheel)
282 IMPLEMENT_CALLBACK_FUNC_ARG2(Motion)
283 IMPLEMENT_CALLBACK_FUNC_ARG2_2NAME(PassiveMotion,Passive)
284 IMPLEMENT_CALLBACK_FUNC_ARG1(Entry)
285 /* glutWMCloseFunc is an alias for glutCloseFunc; both set the window's Destroy callback */
286 IMPLEMENT_CALLBACK_FUNC_ARG0_2NAME(Close,Destroy)
287 IMPLEMENT_CALLBACK_FUNC_ARG0_2NAME(WMClose,Destroy)
288 IMPLEMENT_CALLBACK_FUNC_ARG0(OverlayDisplay)
289 IMPLEMENT_CALLBACK_FUNC_ARG1(WindowStatus)
290 IMPLEMENT_CALLBACK_FUNC_ARG2(ButtonBox)
291 IMPLEMENT_CALLBACK_FUNC_ARG2(Dials)
292 IMPLEMENT_CALLBACK_FUNC_ARG2(TabletMotion)
293 IMPLEMENT_CALLBACK_FUNC_ARG4(TabletButton)
294 IMPLEMENT_CALLBACK_FUNC_ARG2(MultiEntry)
295 IMPLEMENT_CALLBACK_FUNC_ARG5(MultiButton)
296 IMPLEMENT_CALLBACK_FUNC_ARG3(MultiMotion)
297 IMPLEMENT_CALLBACK_FUNC_ARG3(MultiPassive)
298 IMPLEMENT_CALLBACK_FUNC_ARG0(InitContext)
299 IMPLEMENT_CALLBACK_FUNC_ARG1(AppStatus)
302 * Sets the Display callback for the current window
304 void FGAPIENTRY glutDisplayFuncUcall( FGCBDisplayUC callback, FGCBUserData userData )
306 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFuncUcall" );
308 fgError( "Fatal error in program. NULL display callback not "
309 "permitted in GLUT 3.0+ or freeglut 2.0.1+" );
310 SET_CALLBACK( Display );
313 static void fghDisplayFuncCallback( FGCBUserData userData )
315 FGCBDisplay callback = (FGCBDisplay)userData;
319 void FGAPIENTRY glutDisplayFunc( FGCBDisplay callback )
321 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFunc" );
323 glutDisplayFuncUcall( fghDisplayFuncCallback, (FGCBUserData)callback );
325 glutDisplayFuncUcall( NULL, NULL );
328 void fghDefaultReshape( int width, int height, FGCBUserData userData )
330 glViewport( 0, 0, width, height );
333 void FGAPIENTRY glutReshapeFuncUcall( FGCBReshapeUC callback, FGCBUserData userData )
335 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFuncUcall" );
339 callback = fghDefaultReshape;
343 SET_CALLBACK( Reshape );
346 static void fghReshapeFuncCallback( int width, int height, FGCBUserData userData )
348 FGCBReshape callback = (FGCBReshape)userData;
349 callback( width, height );
352 void FGAPIENTRY glutReshapeFunc( FGCBReshape callback )
354 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFunc" );
356 glutReshapeFuncUcall( fghReshapeFuncCallback, (FGCBUserData)callback );
358 glutReshapeFuncUcall( NULL, NULL );
362 * Sets the Visibility callback for the current window.
363 * NB: the Visibility func is deprecated in favor of the WindowStatus func,
364 * which provides more detail. The visibility func callback is implemented
365 * as a translation step from the windowStatus func. When the user sets the
366 * windowStatus func, any visibility func is overwritten.
367 * DEVELOPER NOTE: in the library, only invoke the window status func, this
368 * gets automatically translated to the visibility func if thats what the
370 * window status is kind of anemic on win32 as there are no window messages
371 * to notify us that the window is covered by other windows or not.
372 * Should one want to query this, see
373 * http://stackoverflow.com/questions/5445889/get-which-process-window-is-actually-visible-in-c-sharp
374 * for an implementation outline (but it would be polling based, not push based).
376 static void fghVisibility( int status, FGCBUserData userData )
380 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Visibility Callback" );
381 freeglut_return_if_fail( fgStructure.CurrentWindow );
383 /* Translate window status func states to visibility states */
384 if( ( GLUT_HIDDEN == status ) || ( GLUT_FULLY_COVERED == status ) )
385 vis_status = GLUT_NOT_VISIBLE;
386 else /* GLUT_FULLY_RETAINED, GLUT_PARTIALLY_RETAINED */
387 vis_status = GLUT_VISIBLE;
389 INVOKE_WCB( *( fgStructure.CurrentWindow ), Visibility, ( vis_status ) );
392 void FGAPIENTRY glutVisibilityFuncUcall( FGCBVisibilityUC callback, FGCBUserData userData )
394 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFuncUcall" );
401 SET_CALLBACK( Visibility );
404 glutWindowStatusFuncUcall( fghVisibility, NULL );
406 glutWindowStatusFuncUcall( NULL, NULL );
409 static void fghVisibilityFuncCallback( int visibility, FGCBUserData userData )
411 FGCBVisibility callback = (FGCBVisibility)userData;
412 callback( visibility );
415 void FGAPIENTRY glutVisibilityFunc( FGCBVisibility callback )
417 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFunc" );
419 glutVisibilityFuncUcall( fghVisibilityFuncCallback, (FGCBUserData)callback );
421 glutVisibilityFuncUcall( NULL, NULL );
425 * Sets the joystick callback and polling rate for the current window
427 void FGAPIENTRY glutJoystickFuncUcall( FGCBJoystickUC callback, int pollInterval, FGCBUserData userData )
429 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFuncUcall" );
430 fgInitialiseJoysticks ();
433 fgStructure.CurrentWindow->State.JoystickPollRate <= 0 || /* Joystick callback was disabled */
434 !FETCH_WCB(*fgStructure.CurrentWindow,Joystick)
437 callback && ( pollInterval > 0 ) /* but is now enabled */
439 ++fgState.NumActiveJoysticks;
441 fgStructure.CurrentWindow->State.JoystickPollRate > 0 && /* Joystick callback was enabled */
442 FETCH_WCB(*fgStructure.CurrentWindow,Joystick)
445 !callback || ( pollInterval <= 0 ) /* but is now disabled */
447 --fgState.NumActiveJoysticks;
449 SET_CALLBACK( Joystick );
450 fgStructure.CurrentWindow->State.JoystickPollRate = pollInterval;
452 /* set last poll time such that joystick will be polled asap */
453 fgStructure.CurrentWindow->State.JoystickLastPoll = fgElapsedTime();
454 if (fgStructure.CurrentWindow->State.JoystickLastPoll < pollInterval)
455 fgStructure.CurrentWindow->State.JoystickLastPoll = 0;
457 fgStructure.CurrentWindow->State.JoystickLastPoll -= pollInterval;
460 static void fghJoystickFuncCallback( unsigned int buttons, int axis0, int axis1, int axis2, FGCBUserData userData )
462 FGCBJoystick callback = (FGCBJoystick)userData;
463 callback( buttons, axis0, axis1, axis2 );
466 void FGAPIENTRY glutJoystickFunc( FGCBJoystick callback, int pollInterval )
468 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFunc" );
470 glutJoystickFuncUcall( fghJoystickFuncCallback, pollInterval, (FGCBUserData)callback );
472 glutJoystickFuncUcall( NULL, pollInterval, NULL );
476 * Sets the spaceball motion callback for the current window
478 void FGAPIENTRY glutSpaceballMotionFuncUcall( FGCBSpaceMotionUC callback, FGCBUserData userData )
480 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFuncUcall" );
481 fgInitialiseSpaceball();
483 SET_CALLBACK( SpaceMotion );
486 static void fghSpaceballMotionFuncCallback( int x, int y, int z, FGCBUserData userData )
488 FGCBSpaceMotion callback = (FGCBSpaceMotion)userData;
492 void FGAPIENTRY glutSpaceballMotionFunc( FGCBSpaceMotion callback )
494 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFunc" );
496 glutSpaceballMotionFuncUcall( fghSpaceballMotionFuncCallback, (FGCBUserData)callback );
498 glutSpaceballMotionFuncUcall( NULL, NULL );
502 * Sets the spaceball rotate callback for the current window
504 void FGAPIENTRY glutSpaceballRotateFuncUcall( FGCBSpaceRotationUC callback, FGCBUserData userData )
506 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFuncUcall" );
507 fgInitialiseSpaceball();
509 SET_CALLBACK( SpaceRotation );
512 static void fghSpaceballRotateFuncCallback( int x, int y, int z, FGCBUserData userData )
514 FGCBSpaceRotation callback = (FGCBSpaceRotation)userData;
518 void FGAPIENTRY glutSpaceballRotateFunc( FGCBSpaceRotation callback )
520 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFunc" );
522 glutSpaceballRotateFuncUcall( fghSpaceballRotateFuncCallback, (FGCBUserData)callback );
524 glutSpaceballRotateFuncUcall( NULL, NULL );
528 * Sets the spaceball button callback for the current window
530 void FGAPIENTRY glutSpaceballButtonFuncUcall( FGCBSpaceButtonUC callback, FGCBUserData userData )
532 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFuncUcall" );
533 fgInitialiseSpaceball();
535 SET_CALLBACK( SpaceButton );
538 static void fghSpaceballButtonFuncCallback( int button, int buttonState, FGCBUserData userData )
540 FGCBSpaceButton callback = (FGCBSpaceButton)userData;
541 callback( button, buttonState );
544 void FGAPIENTRY glutSpaceballButtonFunc( FGCBSpaceButton callback )
546 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFunc" );
548 glutSpaceballButtonFuncUcall( fghSpaceballButtonFuncCallback, (FGCBUserData)callback );
550 glutSpaceballButtonFuncUcall( NULL, NULL );
553 /*** END OF FILE ***/