Fixed warnings on Linux where GCC under padantic complained ISO C casting wasn't...
[freeglut] / src / fg_callbacks.c
1 /*
2  * fg_callbacks.c
3  *
4  * The callbacks setting methods.
5  *
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
9  *
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:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
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.
26  */
27
28 #include <GL/freeglut.h>
29 #include "fg_internal.h"
30
31 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
32
33 /*
34  * Global callbacks.
35  */
36
37 /* Sets the global idle callback */
38 void FGAPIENTRY glutIdleFuncUcall( FGCBIdleUC callback, FGCBUserData userData )
39 {
40     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIdleFuncUcall" );
41     fgState.IdleCallback = callback;
42     fgState.IdleCallbackData = userData;
43 }
44
45 IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0(Idle)
46
47 /* Creates a timer and sets its callback */
48 void FGAPIENTRY glutTimerFuncUcall( unsigned int timeOut, FGCBTimerUC callback, int timerID, FGCBUserData userData )
49 {
50     SFG_Timer *timer, *node;
51
52     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFuncUcall" );
53
54     if( (timer = fgState.FreeTimers.Last) )
55     {
56         fgListRemove( &fgState.FreeTimers, &timer->Node );
57     }
58     else
59     {
60         if( ! (timer = malloc(sizeof(SFG_Timer))) )
61             fgError( "Fatal error: "
62                      "Memory allocation failure in glutTimerFunc()" );
63     }
64
65     timer->Callback     = callback;
66     timer->CallbackData = userData;
67     timer->ID           = timerID;
68     timer->TriggerTime  = fgElapsedTime() + timeOut;
69
70     /* Insert such that timers are sorted by end-time */
71     for( node = fgState.Timers.First; node; node = node->Node.Next )
72     {
73         if( node->TriggerTime > timer->TriggerTime )
74             break;
75     }
76
77     fgListInsert( &fgState.Timers, &node->Node, &timer->Node );
78 }
79
80 IMPLEMENT_CALLBACK_FUNC_CB_ARG1(Timer, Timer)
81
82 void FGAPIENTRY glutTimerFunc( unsigned int timeOut, FGCBTimer callback, int timerID )
83 {
84     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFunc" );
85     if( callback )
86     {
87         FGCBTimer* reference = &callback;
88         glutTimerFuncUcall( timeOut, fghTimerFuncCallback, timerID, *((FGCBUserData*)reference) );
89     }
90     else
91         glutTimerFuncUcall( timeOut, NULL, timerID, NULL );
92 }
93
94 /* Deprecated version of glutMenuStatusFunc callback setting method */
95 void FGAPIENTRY glutMenuStateFunc( FGCBMenuState callback )
96 {
97     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStateFunc" );
98     fgState.MenuStateCallback = callback;
99 }
100
101 /* Sets the global menu status callback for the current window */
102 void FGAPIENTRY glutMenuStatusFuncUcall( FGCBMenuStatusUC callback, FGCBUserData userData )
103 {
104     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStatusFuncUcall" );
105     fgState.MenuStatusCallback = callback;
106     fgState.MenuStatusCallbackData = userData;
107 }
108
109 IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3(MenuStatus)
110
111 /*
112  * Menu specific callbacks.
113  */
114 /* Callback upon menu destruction */
115 void FGAPIENTRY glutMenuDestroyFuncUcall( FGCBDestroyUC callback, FGCBUserData userData )
116 {
117     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFuncUcall" );
118     if( fgStructure.CurrentMenu )
119     {
120         fgStructure.CurrentMenu->Destroy = callback;
121         fgStructure.CurrentMenu->DestroyData = userData;
122     }
123 }
124
125 IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0_2NAME(MenuDestroy, Destroy)
126
127 /* Implement all these callback setter functions... */
128 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(Position)
129 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3_USER(Keyboard,unsigned char,int,int)
130 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3_USER(KeyboardUp,unsigned char,int,int)
131 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3(Special)
132 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3(SpecialUp)
133 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG4(Mouse)
134 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG4(MouseWheel)
135 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(Motion)
136 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2_2NAME(PassiveMotion,Passive)
137 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG1(Entry)
138 /* glutWMCloseFunc is an alias for glutCloseFunc; both set the window's Destroy callback */
139 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0_2NAME(Close,Destroy)
140 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0_2NAME(WMClose,Destroy)
141 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0(OverlayDisplay)
142 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG1(WindowStatus)
143 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(ButtonBox)
144 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(Dials)
145 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(TabletMotion)
146 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG4(TabletButton)
147 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(MultiEntry)
148 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG5(MultiButton)
149 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3(MultiMotion)
150 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3(MultiPassive)
151 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0(InitContext)
152 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG1(AppStatus)
153
154 /*
155  * Sets the Display callback for the current window
156  */
157 void FGAPIENTRY glutDisplayFuncUcall( FGCBDisplayUC callback, FGCBUserData userData )
158 {
159     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFuncUcall" );
160     if( !callback )
161         fgError( "Fatal error in program.  NULL display callback not "
162                  "permitted in GLUT 3.0+ or freeglut 2.0.1+" );
163     SET_CURRENT_WINDOW_CALLBACK( Display );
164 }
165
166 IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0(Display)
167
168 void fghDefaultReshape( int width, int height, FGCBUserData userData )
169 {
170     glViewport( 0, 0, width, height );
171 }
172
173 void FGAPIENTRY glutReshapeFuncUcall( FGCBReshapeUC callback, FGCBUserData userData )
174 {
175     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFuncUcall" );
176     
177     if( !callback )
178     {
179         callback = fghDefaultReshape;
180         userData = NULL;
181     }
182
183     SET_CURRENT_WINDOW_CALLBACK( Reshape );
184 }
185
186 IMPLEMENT_GLUT_CALLBACK_FUNC_ARG2(Reshape)
187
188 /*
189  * Sets the Visibility callback for the current window.
190  * NB: the Visibility func is deprecated in favor of the WindowStatus func,
191  * which provides more detail. The visibility func callback is implemented
192  * as a translation step from the windowStatus func. When the user sets the
193  * windowStatus func, any visibility func is overwritten.
194  * DEVELOPER NOTE: in the library, only invoke the window status func, this
195  * gets automatically translated to the visibility func if thats what the
196  * user has set.
197  * window status is kind of anemic on win32 as there are no window messages
198  * to notify us that the window is covered by other windows or not.
199  * Should one want to query this, see
200  * http://stackoverflow.com/questions/5445889/get-which-process-window-is-actually-visible-in-c-sharp
201  * for an implementation outline (but it would be polling based, not push based).
202  */
203 static void fghVisibility( int status, FGCBUserData userData )
204 {
205     int vis_status;
206
207     FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Visibility Callback" );
208     freeglut_return_if_fail( fgStructure.CurrentWindow );
209
210     /* Translate window status func states to visibility states */
211     if( ( status == GLUT_HIDDEN)  || ( status == GLUT_FULLY_COVERED) )
212         vis_status = GLUT_NOT_VISIBLE;
213     else    /* GLUT_FULLY_RETAINED, GLUT_PARTIALLY_RETAINED */
214         vis_status = GLUT_VISIBLE;
215
216     INVOKE_WCB( *( fgStructure.CurrentWindow ), Visibility, ( vis_status ) );
217 }
218
219 void FGAPIENTRY glutVisibilityFuncUcall( FGCBVisibilityUC callback, FGCBUserData userData )
220 {
221     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFuncUcall" );
222
223     if ( !callback )
224     {
225         userData = NULL;
226     }
227
228     SET_CURRENT_WINDOW_CALLBACK( Visibility );
229
230     if( callback )
231         glutWindowStatusFuncUcall( fghVisibility, NULL );
232     else
233         glutWindowStatusFuncUcall( NULL, NULL );
234 }
235
236 IMPLEMENT_GLUT_CALLBACK_FUNC_ARG1(Visibility)
237
238 /*
239  * Sets the joystick callback and polling rate for the current window
240  */
241 void FGAPIENTRY glutJoystickFuncUcall( FGCBJoystickUC callback, int pollInterval, FGCBUserData userData )
242 {
243     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFuncUcall" );
244     fgInitialiseJoysticks ();
245
246     if ( (
247            fgStructure.CurrentWindow->State.JoystickPollRate <= 0 ||        /* Joystick callback was disabled */
248            !FETCH_WCB(*fgStructure.CurrentWindow,Joystick)
249          ) &&
250          ( 
251            callback && ( pollInterval > 0 )                                 /* but is now enabled */
252          ) )
253         ++fgState.NumActiveJoysticks;
254     else if ( ( 
255                 fgStructure.CurrentWindow->State.JoystickPollRate > 0 &&    /* Joystick callback was enabled */
256                 FETCH_WCB(*fgStructure.CurrentWindow,Joystick)
257               ) &&  
258               ( 
259                 !callback || ( pollInterval <= 0 )                          /* but is now disabled */
260               ) )
261         --fgState.NumActiveJoysticks;
262
263     SET_CURRENT_WINDOW_CALLBACK( Joystick );
264     fgStructure.CurrentWindow->State.JoystickPollRate = pollInterval;
265
266     /* set last poll time such that joystick will be polled asap */
267     fgStructure.CurrentWindow->State.JoystickLastPoll = fgElapsedTime();
268     if (fgStructure.CurrentWindow->State.JoystickLastPoll < pollInterval)
269         fgStructure.CurrentWindow->State.JoystickLastPoll = 0;
270     else
271         fgStructure.CurrentWindow->State.JoystickLastPoll -= pollInterval;
272 }
273
274 static void fghJoystickFuncCallback( unsigned int buttons, int axis0, int axis1, int axis2, FGCBUserData userData )
275 {
276     FGCBJoystick* callback = (FGCBJoystick*)&userData;
277     (*callback)( buttons, axis0, axis1, axis2 );
278 }
279
280 void FGAPIENTRY glutJoystickFunc( FGCBJoystick callback, int pollInterval )
281 {
282     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFunc" );
283     if( callback )
284     {
285         FGCBJoystick* reference = &callback;
286         glutJoystickFuncUcall( fghJoystickFuncCallback, pollInterval, *((FGCBUserData*)reference) );
287     }
288     else
289         glutJoystickFuncUcall( NULL, pollInterval, NULL );
290 }
291
292 /*
293  * Sets the spaceball motion callback for the current window
294  */
295 void FGAPIENTRY glutSpaceballMotionFuncUcall( FGCBSpaceMotionUC callback, FGCBUserData userData )
296 {
297     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFuncUcall" );
298     fgInitialiseSpaceball();
299
300     SET_CURRENT_WINDOW_CALLBACK( SpaceMotion );
301 }
302
303 IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3_2NAME(SpaceballMotion, SpaceMotion)
304
305 /*
306  * Sets the spaceball rotate callback for the current window
307  */
308 void FGAPIENTRY glutSpaceballRotateFuncUcall( FGCBSpaceRotationUC callback, FGCBUserData userData )
309 {
310     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFuncUcall" );
311     fgInitialiseSpaceball();
312
313     SET_CURRENT_WINDOW_CALLBACK( SpaceRotation );
314 }
315
316 IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3_2NAME(SpaceballRotate, SpaceRotation)
317
318 /*
319  * Sets the spaceball button callback for the current window
320  */
321 void FGAPIENTRY glutSpaceballButtonFuncUcall( FGCBSpaceButtonUC callback, FGCBUserData userData )
322 {
323     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFuncUcall" );
324     fgInitialiseSpaceball();
325
326     SET_CURRENT_WINDOW_CALLBACK( SpaceButton );
327 }
328
329 IMPLEMENT_GLUT_CALLBACK_FUNC_ARG2_2NAME(SpaceballButton, SpaceButton)
330
331 /*** END OF FILE ***/