Setting the line endings and keywords on a bunch of new text files
[freeglut] / src / Common / freeglut_main.c
1 /*
2  * freeglut_main.c
3  *
4  * The windows message processing 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 "freeglut_internal.h"
30 #ifdef HAVE_ERRNO_H
31 #    include <errno.h>
32 #endif
33 #include <stdarg.h>
34 #ifdef  HAVE_VFPRINTF
35 #    define VFPRINTF(s,f,a) vfprintf((s),(f),(a))
36 #elif defined(HAVE__DOPRNT)
37 #    define VFPRINTF(s,f,a) _doprnt((f),(a),(s))
38 #else
39 #    define VFPRINTF(s,f,a)
40 #endif
41
42 #ifdef _WIN32_WCE
43
44 typedef struct GXDisplayProperties GXDisplayProperties;
45 typedef struct GXKeyList GXKeyList;
46 #include <gx.h>
47
48 typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int);
49 typedef int (*GXOPENINPUT)();
50
51 GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL;
52 GXOPENINPUT GXOpenInput_ = NULL;
53
54 struct GXKeyList gxKeyList;
55
56 #endif /* _WIN32_WCE */
57
58 /*
59  * Try to get the maximum value allowed for ints, falling back to the minimum
60  * guaranteed by ISO C99 if there is no suitable header.
61  */
62 #ifdef HAVE_LIMITS_H
63 #    include <limits.h>
64 #endif
65 #ifndef INT_MAX
66 #    define INT_MAX 32767
67 #endif
68
69 #ifndef MIN
70 #    define MIN(a,b) (((a)<(b)) ? (a) : (b))
71 #endif
72
73 extern void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height );
74 extern void fgPlatformDisplayWindow ( SFG_Window *window );
75 extern unsigned long fgPlatformSystemTime ( void );
76 extern void fgPlatformSleepForEvents( long msec );
77 extern void fgPlatformProcessSingleEvent ( void );
78 extern void fgPlatformMainLoopPreliminaryWork ( void );
79
80
81
82
83 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
84
85 static void fghReshapeWindow ( SFG_Window *window, int width, int height )
86 {
87     SFG_Window *current_window = fgStructure.CurrentWindow;
88
89     freeglut_return_if_fail( window != NULL );
90
91         fgPlatformReshapeWindow ( window, width, height );
92
93     if( FETCH_WCB( *window, Reshape ) )
94         INVOKE_WCB( *window, Reshape, ( width, height ) );
95     else
96     {
97         fgSetWindow( window );
98         glViewport( 0, 0, width, height );
99     }
100
101     /*
102      * Force a window redraw.  In Windows at least this is only a partial
103      * solution:  if the window is increasing in size in either dimension,
104      * the already-drawn part does not get drawn again and things look funny.
105      * But without this we get this bad behaviour whenever we resize the
106      * window.
107      */
108     window->State.Redisplay = GL_TRUE;
109
110     if( window->IsMenu )
111         fgSetWindow( current_window );
112 }
113
114 /*
115  * Calls a window's redraw method. This is used when
116  * a redraw is forced by the incoming window messages.
117  */
118 void fghRedrawWindow ( SFG_Window *window )
119 {
120     SFG_Window *current_window = fgStructure.CurrentWindow;
121
122     freeglut_return_if_fail( window );
123     freeglut_return_if_fail( FETCH_WCB ( *window, Display ) );
124
125     window->State.Redisplay = GL_FALSE;
126
127     freeglut_return_if_fail( window->State.Visible );
128
129     fgSetWindow( window );
130
131     if( window->State.NeedToResize )
132     {
133         fghReshapeWindow(
134             window,
135             window->State.Width,
136             window->State.Height
137         );
138
139         window->State.NeedToResize = GL_FALSE;
140     }
141
142     INVOKE_WCB( *window, Display, ( ) );
143
144     fgSetWindow( current_window );
145 }
146
147
148 static void fghcbDisplayWindow( SFG_Window *window,
149                                 SFG_Enumerator *enumerator )
150 {
151     if( window->State.Redisplay &&
152         window->State.Visible )
153     {
154         window->State.Redisplay = GL_FALSE;
155                 fgPlatformDisplayWindow ( window );
156     }
157
158     fgEnumSubWindows( window, fghcbDisplayWindow, enumerator );
159 }
160
161 /*
162  * Make all windows perform a display call
163  */
164 static void fghDisplayAll( void )
165 {
166     SFG_Enumerator enumerator;
167
168     enumerator.found = GL_FALSE;
169     enumerator.data  =  NULL;
170
171     fgEnumWindows( fghcbDisplayWindow, &enumerator );
172 }
173
174 /*
175  * Window enumerator callback to check for the joystick polling code
176  */
177 static void fghcbCheckJoystickPolls( SFG_Window *window,
178                                      SFG_Enumerator *enumerator )
179 {
180     long int checkTime = fgElapsedTime( );
181
182     if( window->State.JoystickLastPoll + window->State.JoystickPollRate <=
183         checkTime )
184     {
185 #if !defined(_WIN32_WCE)
186         fgJoystickPollWindow( window );
187 #endif /* !defined(_WIN32_WCE) */
188         window->State.JoystickLastPoll = checkTime;
189     }
190
191     fgEnumSubWindows( window, fghcbCheckJoystickPolls, enumerator );
192 }
193
194 /*
195  * Check all windows for joystick polling
196  */
197 static void fghCheckJoystickPolls( void )
198 {
199     SFG_Enumerator enumerator;
200
201     enumerator.found = GL_FALSE;
202     enumerator.data  =  NULL;
203
204     fgEnumWindows( fghcbCheckJoystickPolls, &enumerator );
205 }
206
207 /*
208  * Check the global timers
209  */
210 static void fghCheckTimers( void )
211 {
212     long checkTime = fgElapsedTime( );
213
214     while( fgState.Timers.First )
215     {
216         SFG_Timer *timer = fgState.Timers.First;
217
218         if( timer->TriggerTime > checkTime )
219             break;
220
221         fgListRemove( &fgState.Timers, &timer->Node );
222         fgListAppend( &fgState.FreeTimers, &timer->Node );
223
224         timer->Callback( timer->ID );
225     }
226 }
227
228  
229 /* Platform-dependent time in milliseconds, as an unsigned 32-bit integer.
230  * This value wraps every 49.7 days, but integer overflows cancel
231  * when subtracting an initial start time, unless the total time exceeds
232  * 32-bit, where the GLUT API return value is also overflowed.
233  */  
234 unsigned long fgSystemTime(void)
235 {
236         return fgPlatformSystemTime ();
237 }
238   
239 /*
240  * Elapsed Time
241  */
242 long fgElapsedTime( void )
243 {
244     return (long) (fgSystemTime() - fgState.Time);
245 }
246
247 /*
248  * Error Messages.
249  */
250 void fgError( const char *fmt, ... )
251 {
252     va_list ap;
253
254     if (fgState.ErrorFunc) {
255
256         va_start( ap, fmt );
257
258         /* call user set error handler here */
259         fgState.ErrorFunc(fmt, ap);
260
261         va_end( ap );
262
263     } else {
264
265         va_start( ap, fmt );
266
267         fprintf( stderr, "freeglut ");
268         if( fgState.ProgramName )
269             fprintf( stderr, "(%s): ", fgState.ProgramName );
270         VFPRINTF( stderr, fmt, ap );
271         fprintf( stderr, "\n" );
272
273         va_end( ap );
274
275         if ( fgState.Initialised )
276             fgDeinitialize ();
277
278         exit( 1 );
279     }
280 }
281
282 void fgWarning( const char *fmt, ... )
283 {
284     va_list ap;
285
286     if (fgState.WarningFunc) {
287
288         va_start( ap, fmt );
289
290         /* call user set warning handler here */
291         fgState.WarningFunc(fmt, ap);
292
293         va_end( ap );
294
295     } else {
296
297         va_start( ap, fmt );
298
299         fprintf( stderr, "freeglut ");
300         if( fgState.ProgramName )
301             fprintf( stderr, "(%s): ", fgState.ProgramName );
302         VFPRINTF( stderr, fmt, ap );
303         fprintf( stderr, "\n" );
304
305         va_end( ap );
306     }
307 }
308
309
310 /*
311  * Indicates whether Joystick events are being used by ANY window.
312  *
313  * The current mechanism is to walk all of the windows and ask if
314  * there is a joystick callback.  We have a short-circuit early
315  * return if we find any joystick handler registered.
316  *
317  * The real way to do this is to make use of the glutTimer() API
318  * to more cleanly re-implement the joystick API.  Then, this code
319  * and all other "joystick timer" code can be yanked.
320  *
321  */
322 static void fghCheckJoystickCallback( SFG_Window* w, SFG_Enumerator* e)
323 {
324     if( FETCH_WCB( *w, Joystick ) )
325     {
326         e->found = GL_TRUE;
327         e->data = w;
328     }
329     fgEnumSubWindows( w, fghCheckJoystickCallback, e );
330 }
331 static int fghHaveJoystick( void )
332 {
333     SFG_Enumerator enumerator;
334
335     enumerator.found = GL_FALSE;
336     enumerator.data = NULL;
337     fgEnumWindows( fghCheckJoystickCallback, &enumerator );
338     return !!enumerator.data;
339 }
340 static void fghHavePendingRedisplaysCallback( SFG_Window* w, SFG_Enumerator* e)
341 {
342     if( w->State.Redisplay && w->State.Visible )
343     {
344         e->found = GL_TRUE;
345         e->data = w;
346     }
347     fgEnumSubWindows( w, fghHavePendingRedisplaysCallback, e );
348 }
349 static int fghHavePendingRedisplays (void)
350 {
351     SFG_Enumerator enumerator;
352
353     enumerator.found = GL_FALSE;
354     enumerator.data = NULL;
355     fgEnumWindows( fghHavePendingRedisplaysCallback, &enumerator );
356     return !!enumerator.data;
357 }
358 /*
359  * Returns the number of GLUT ticks (milliseconds) till the next timer event.
360  */
361 static long fghNextTimer( void )
362 {
363     long ret = INT_MAX;
364     SFG_Timer *timer = fgState.Timers.First;
365
366     if( timer )
367         ret = timer->TriggerTime - fgElapsedTime();
368     if( ret < 0 )
369         ret = 0;
370
371     return ret;
372 }
373
374 static void fghSleepForEvents( void )
375 {
376     long msec;
377
378     if( fgState.IdleCallback || fghHavePendingRedisplays( ) )
379         return;
380
381     msec = fghNextTimer( );
382     /* XXX Use GLUT timers for joysticks... */
383     /* XXX Dumb; forces granularity to .01sec */
384     if( fghHaveJoystick( ) && ( msec > 10 ) )     
385         msec = 10;
386
387         fgPlatformSleepForEvents ( msec );
388 }
389
390
391 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
392
393 /*
394  * Executes a single iteration in the freeglut processing loop.
395  */
396 void FGAPIENTRY glutMainLoopEvent( void )
397 {
398         fgPlatformProcessSingleEvent ();
399
400     if( fgState.Timers.First )
401         fghCheckTimers( );
402     fghCheckJoystickPolls( );
403     fghDisplayAll( );
404
405     fgCloseWindows( );
406 }
407
408 /*
409  * Enters the freeglut processing loop.
410  * Stays until the "ExecState" changes to "GLUT_EXEC_STATE_STOP".
411  */
412 void FGAPIENTRY glutMainLoop( void )
413 {
414     int action;
415
416     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoop" );
417
418         fgPlatformMainLoopPreliminaryWork ();
419
420     fgState.ExecState = GLUT_EXEC_STATE_RUNNING ;
421     while( fgState.ExecState == GLUT_EXEC_STATE_RUNNING )
422     {
423         SFG_Window *window;
424
425         glutMainLoopEvent( );
426         /*
427          * Step through the list of windows, seeing if there are any
428          * that are not menus
429          */
430         for( window = ( SFG_Window * )fgStructure.Windows.First;
431              window;
432              window = ( SFG_Window * )window->Node.Next )
433             if ( ! ( window->IsMenu ) )
434                 break;
435
436         if( ! window )
437             fgState.ExecState = GLUT_EXEC_STATE_STOP;
438         else
439         {
440             if( fgState.IdleCallback )
441             {
442                 if( fgStructure.CurrentWindow &&
443                     fgStructure.CurrentWindow->IsMenu )
444                     /* fail safe */
445                     fgSetWindow( window );
446                 fgState.IdleCallback( );
447             }
448
449             fghSleepForEvents( );
450         }
451     }
452
453     /*
454      * When this loop terminates, destroy the display, state and structure
455      * of a freeglut session, so that another glutInit() call can happen
456      *
457      * Save the "ActionOnWindowClose" because "fgDeinitialize" resets it.
458      */
459     action = fgState.ActionOnWindowClose;
460     fgDeinitialize( );
461     if( action == GLUT_ACTION_EXIT )
462         exit( 0 );
463 }
464
465 /*
466  * Leaves the freeglut processing loop.
467  */
468 void FGAPIENTRY glutLeaveMainLoop( void )
469 {
470     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveMainLoop" );
471     fgState.ExecState = GLUT_EXEC_STATE_STOP ;
472 }
473
474
475
476 /*** END OF FILE ***/