6eff0bf4e1d8e97ec87ca477421370480f7c7efc
[freeglut] / src / fg_callbacks.c
1 /*
2  * freeglut_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  * All of the callbacks setting methods can be generalized to this:
35  */
36 #define SET_CALLBACK(a)                                         \
37 do                                                              \
38 {                                                               \
39     if( fgStructure.CurrentWindow == NULL )                     \
40         return;                                                 \
41     SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback ); \
42 } while( 0 )
43
44 /*
45  * Sets the Display callback for the current window
46  */
47 void FGAPIENTRY glutDisplayFunc( void (* callback)( void ) )
48 {
49     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFunc" );
50     if( !callback )
51         fgError( "Fatal error in program.  NULL display callback not "
52                  "permitted in GLUT 3.0+ or freeglut 2.0.1+" );
53     SET_CALLBACK( Display );
54 }
55
56 /*
57  * Sets the Reshape callback for the current window
58  */
59 void FGAPIENTRY glutReshapeFunc( void (* callback)( int, int ) )
60 {
61     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFunc" );
62     SET_CALLBACK( Reshape );
63 }
64
65 /*
66  * Sets the Keyboard callback for the current window
67  */
68 void FGAPIENTRY glutKeyboardFunc( void (* callback)
69                                   ( unsigned char, int, int ) )
70 {
71     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutKeyboardFunc" );
72     SET_CALLBACK( Keyboard );
73 }
74
75 /*
76  * Sets the Special callback for the current window
77  */
78 void FGAPIENTRY glutSpecialFunc( void (* callback)( int, int, int ) )
79 {
80     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpecialFunc" );
81     SET_CALLBACK( Special );
82 }
83
84 /*
85  * Sets the global idle callback
86  */
87 void FGAPIENTRY glutIdleFunc( void (* callback)( void ) )
88 {
89     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIdleFunc" );
90     fgState.IdleCallback = callback;
91 }
92
93 /*
94  * Sets the Timer callback for the current window
95  */
96 void FGAPIENTRY glutTimerFunc( unsigned int timeOut, void (* callback)( int ),
97                                int timerID )
98 {
99     SFG_Timer *timer, *node;
100
101     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFunc" );
102
103     if( (timer = fgState.FreeTimers.Last) )
104     {
105         fgListRemove( &fgState.FreeTimers, &timer->Node );
106     }
107     else
108     {
109         if( ! (timer = malloc(sizeof(SFG_Timer))) )
110             fgError( "Fatal error: "
111                      "Memory allocation failure in glutTimerFunc()" );
112     }
113
114     timer->Callback  = callback;
115     timer->ID        = timerID;
116     timer->TriggerTime = fgElapsedTime() + timeOut;
117
118     for( node = fgState.Timers.First; node; node = node->Node.Next )
119     {
120         if( node->TriggerTime > timer->TriggerTime )
121             break;
122     }
123
124     fgListInsert( &fgState.Timers, &node->Node, &timer->Node );
125 }
126
127 /*
128  * Sets the Visibility callback for the current window.
129  */
130 static void fghVisibility( int status )
131 {
132     int glut_status = GLUT_VISIBLE;
133
134     FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Visibility Callback" );
135     freeglut_return_if_fail( fgStructure.CurrentWindow );
136
137     if( ( GLUT_HIDDEN == status )  || ( GLUT_FULLY_COVERED == status ) )
138         glut_status = GLUT_NOT_VISIBLE;
139     INVOKE_WCB( *( fgStructure.CurrentWindow ), Visibility, ( glut_status ) );
140 }
141
142 void FGAPIENTRY glutVisibilityFunc( void (* callback)( int ) )
143 {
144     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFunc" );
145     SET_CALLBACK( Visibility );
146
147     if( callback )
148         glutWindowStatusFunc( fghVisibility );
149     else
150         glutWindowStatusFunc( NULL );
151 }
152
153 /*
154  * Sets the keyboard key release callback for the current window
155  */
156 void FGAPIENTRY glutKeyboardUpFunc( void (* callback)
157                                     ( unsigned char, int, int ) )
158 {
159     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutKeyboardUpFunc" );
160     SET_CALLBACK( KeyboardUp );
161 }
162
163 /*
164  * Sets the special key release callback for the current window
165  */
166 void FGAPIENTRY glutSpecialUpFunc( void (* callback)( int, int, int ) )
167 {
168     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpecialUpFunc" );
169     SET_CALLBACK( SpecialUp );
170 }
171
172 /*
173  * Sets the joystick callback and polling rate for the current window
174  */
175 void FGAPIENTRY glutJoystickFunc( void (* callback)
176                                   ( unsigned int, int, int, int ),
177                                   int pollInterval )
178 {
179     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFunc" );
180     fgInitialiseJoysticks ();
181
182     if ( ( ( fgStructure.CurrentWindow->State.JoystickPollRate < 0 ) ||
183            !FETCH_WCB(*fgStructure.CurrentWindow,Joystick) ) &&  /* Joystick callback was disabled */
184          ( callback && ( pollInterval >= 0 ) ) )               /* but is now enabled */
185         ++fgState.NumActiveJoysticks;
186     else if ( ( ( fgStructure.CurrentWindow->State.JoystickPollRate >= 0 ) &&
187                 FETCH_WCB(*fgStructure.CurrentWindow,Joystick) ) &&  /* Joystick callback was enabled */
188               ( !callback || ( pollInterval < 0 ) ) )              /* but is now disabled */
189         --fgState.NumActiveJoysticks;
190
191     SET_CALLBACK( Joystick );
192     fgStructure.CurrentWindow->State.JoystickPollRate = pollInterval;
193
194     fgStructure.CurrentWindow->State.JoystickLastPoll =
195         fgElapsedTime() - fgStructure.CurrentWindow->State.JoystickPollRate;
196
197     if( fgStructure.CurrentWindow->State.JoystickLastPoll < 0 )
198         fgStructure.CurrentWindow->State.JoystickLastPoll = 0;
199 }
200
201 /*
202  * Sets the mouse callback for the current window
203  */
204 void FGAPIENTRY glutMouseFunc( void (* callback)( int, int, int, int ) )
205 {
206     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMouseFunc" );
207     SET_CALLBACK( Mouse );
208 }
209
210 /*
211  * Sets the mouse wheel callback for the current window
212  */
213 void FGAPIENTRY glutMouseWheelFunc( void (* callback)( int, int, int, int ) )
214 {
215     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMouseWheelFunc" );
216     SET_CALLBACK( MouseWheel );
217 }
218
219 /*
220  * Sets the mouse motion callback for the current window (one or more buttons
221  * are pressed)
222  */
223 void FGAPIENTRY glutMotionFunc( void (* callback)( int, int ) )
224 {
225     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMotionFunc" );
226     SET_CALLBACK( Motion );
227 }
228
229 /*
230  * Sets the passive mouse motion callback for the current window (no mouse
231  * buttons are pressed)
232  */
233 void FGAPIENTRY glutPassiveMotionFunc( void (* callback)( int, int ) )
234 {
235     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPassiveMotionFunc" );
236     SET_CALLBACK( Passive );
237 }
238
239 /*
240  * Window mouse entry/leave callback
241  */
242 void FGAPIENTRY glutEntryFunc( void (* callback)( int ) )
243 {
244     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutEntryFunc" );
245     SET_CALLBACK( Entry );
246 }
247
248 /*
249  * Window destruction callbacks
250  */
251 void FGAPIENTRY glutCloseFunc( void (* callback)( void ) )
252 {
253     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCloseFunc" );
254     SET_CALLBACK( Destroy );
255 }
256
257 void FGAPIENTRY glutWMCloseFunc( void (* callback)( void ) )
258 {
259     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWMCloseFunc" );
260     glutCloseFunc( callback );
261 }
262
263 /* A. Donev: Destruction callback for menus */
264 void FGAPIENTRY glutMenuDestroyFunc( void (* callback)( void ) )
265 {
266     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFunc" );
267     if( fgStructure.CurrentMenu )
268         fgStructure.CurrentMenu->Destroy = callback;
269 }
270
271 /*
272  * Deprecated version of glutMenuStatusFunc callback setting method
273  */
274 void FGAPIENTRY glutMenuStateFunc( void (* callback)( int ) )
275 {
276     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStateFunc" );
277     fgState.MenuStateCallback = callback;
278 }
279
280 /*
281  * Sets the global menu status callback for the current window
282  */
283 void FGAPIENTRY glutMenuStatusFunc( void (* callback)( int, int, int ) )
284 {
285     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStatusFunc" );
286     fgState.MenuStatusCallback = callback;
287 }
288
289 /*
290  * Sets the overlay display callback for the current window
291  */
292 void FGAPIENTRY glutOverlayDisplayFunc( void (* callback)( void ) )
293 {
294     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutOverlayDisplayFunc" );
295     SET_CALLBACK( OverlayDisplay );
296 }
297
298 /*
299  * Sets the window status callback for the current window
300  */
301 void FGAPIENTRY glutWindowStatusFunc( void (* callback)( int ) )
302 {
303     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWindowStatusFunc" );
304     SET_CALLBACK( WindowStatus );
305 }
306
307 /*
308  * Sets the spaceball motion callback for the current window
309  */
310 void FGAPIENTRY glutSpaceballMotionFunc( void (* callback)( int, int, int ) )
311 {
312     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFunc" );
313     fgInitialiseSpaceball();
314
315     SET_CALLBACK( SpaceMotion );
316 }
317
318 /*
319  * Sets the spaceball rotate callback for the current window
320  */
321 void FGAPIENTRY glutSpaceballRotateFunc( void (* callback)( int, int, int ) )
322 {
323     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFunc" );
324     fgInitialiseSpaceball();
325
326     SET_CALLBACK( SpaceRotation );
327 }
328
329 /*
330  * Sets the spaceball button callback for the current window
331  */
332 void FGAPIENTRY glutSpaceballButtonFunc( void (* callback)( int, int ) )
333 {
334     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFunc" );
335     fgInitialiseSpaceball();
336
337     SET_CALLBACK( SpaceButton );
338 }
339
340 /*
341  * Sets the button box callback for the current window
342  */
343 void FGAPIENTRY glutButtonBoxFunc( void (* callback)( int, int ) )
344 {
345     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutButtonBoxFunc" );
346     SET_CALLBACK( ButtonBox );
347 }
348
349 /*
350  * Sets the dials box callback for the current window
351  */
352 void FGAPIENTRY glutDialsFunc( void (* callback)( int, int ) )
353 {
354     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDialsFunc" );
355     SET_CALLBACK( Dials );
356 }
357
358 /*
359  * Sets the tablet motion callback for the current window
360  */
361 void FGAPIENTRY glutTabletMotionFunc( void (* callback)( int, int ) )
362 {
363     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTabletMotionFunc" );
364     SET_CALLBACK( TabletMotion );
365 }
366
367 /*
368  * Sets the tablet buttons callback for the current window
369  */
370 void FGAPIENTRY glutTabletButtonFunc( void (* callback)( int, int, int, int ) )
371 {
372     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTabletButtonFunc" );
373     SET_CALLBACK( TabletButton );
374 }
375
376 /*
377  * Sets the multi-pointer entry callback for the current window
378  */
379 void FGAPIENTRY glutMultiEntryFunc( void (* callback)(int, int ) )
380 {
381     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMultiEntryFunc" );
382     SET_CALLBACK( MultiEntry );
383 }
384
385 /*
386  * Sets the multi-pointer button callback for the current window
387  */
388 void FGAPIENTRY glutMultiButtonFunc( void (* callback)(int, int, int, int, int ) )
389 {
390     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMultiButtonFunc" );
391     SET_CALLBACK( MultiButton );
392 }
393
394 /*
395  * Sets the multi-pointer motion callback for the current window
396  */
397 void FGAPIENTRY glutMultiMotionFunc( void (* callback)(int, int, int ) )
398 {
399     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMultiMotionFunc" );
400     SET_CALLBACK( MultiMotion );
401 }
402
403 /*
404  * Sets the multi-pointer passive motion callback for the current window
405  */
406 void FGAPIENTRY glutMultiPassiveFunc( void (* callback)(int, int, int ) )
407 {
408     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMultiPassiveFunc" );
409     SET_CALLBACK( MultiPassive );
410 }
411
412 /*
413  * Sets the context reload callback for the current window
414  */
415 void FGAPIENTRY glutInitContextFunc( void (* callback)() )
416 {
417     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutInitContextFunc" );
418     SET_CALLBACK( InitContext );
419 }
420
421 /*
422  * Sets the pause callback for the current window
423  */
424 void FGAPIENTRY glutPauseFunc( void (* callback)() )
425 {
426     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPauseFunc" );
427     SET_CALLBACK( Pause );
428 }
429
430 /*
431  * Sets the resume callback for the current window
432  */
433 void FGAPIENTRY glutResumeFunc( void (* callback)() )
434 {
435     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutResumeFunc" );
436     SET_CALLBACK( Resume );
437 }
438
439 /*** END OF FILE ***/