Timer optimizations.
[freeglut] / src / freeglut_main.c
index 6413363..55e033a 100644 (file)
@@ -83,18 +83,6 @@ static void fghReshapeWindowByHandle ( SFG_WindowHandleType handle,
     XResizeWindow( fgDisplay.Display, window->Window.Handle,
                    width, height );
     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
-    /*
-     * XXX REALLY shouldn't be done.  GLUT docs state that this
-     * XXX isn't even processed immediately, but rather waits
-     * XXX for return to the mainloop.  "This allows multiple
-     * XXX glutReshapeWindow, glutPositionWindow, and glutFullScreen
-     * XXX requests to the same window to be coalesced."  (This is
-     * XXX having some deleterious effect on a sample program of mine.)
-     * XXX Not only does GLUT not flush at this point, GLUT doesn't even
-     * XXX *do* the reshape at this point!  We should probably rip this
-     * XXX out and do what GLUT promises.  It would be more efficient, and
-     * XXX might be more compatible.
-     */
 
 #elif TARGET_HOST_WIN32
 
@@ -168,25 +156,11 @@ static void fghReshapeWindowByHandle ( SFG_WindowHandleType handle,
 static void fghRedrawWindowByHandle ( SFG_WindowHandleType handle )
 {
     SFG_Window* window = fgWindowByHandle( handle );
-    freeglut_return_if_fail( window != NULL );
+    freeglut_return_if_fail( window );
+    freeglut_return_if_fail( FETCH_WCB ( *window, Display ) );
+
+    window->State.Redisplay = GL_FALSE;
 
-    /*
-     * XXX Other than clearing the Redisplay flag or not,
-     * XXX we may as well rely on the INVOK_WCB() doing this
-     * XXX pointer-check.
-     * XXX
-     * XXX If we do not invoke the display because the pointer
-     * XXX is not defined (should never happen, really), then
-     * XXX we may enter an infinite busy-loop trying to update
-     * XXX the window.  Similarly, if we skip because the window
-     * XXX is not visible.  However, if the window becomes visible
-     * XXX at a later time, the window should get its callback
-     * XXX invoked.  I would recommend removing the first check,
-     * XXX and making the second check only affect whether the
-     * XXX callback is invoked---but always clear the flag, if
-     * XXX the {window} pointer is defined.
-     */
-    freeglut_return_if_fail( FETCH_WCB( *window, Display ) );
     freeglut_return_if_fail( window->State.Visible );
 
     if( window->State.NeedToResize )
@@ -205,7 +179,6 @@ static void fghRedrawWindowByHandle ( SFG_WindowHandleType handle )
         fgSetWindow ( current_window );
     }
 
-    window->State.Redisplay = GL_FALSE;
     INVOKE_WCB( *window, Display, ( ) );
 }
 
@@ -215,17 +188,7 @@ static void fghRedrawWindowByHandle ( SFG_WindowHandleType handle )
 static void fghcbDisplayWindow( SFG_Window *window,
                                 SFG_Enumerator *enumerator )
 {
-    /*
-     * XXX Do we need/want to check the callback pointer here?
-     * XXX INVOKE_WCB() will check for us.  Arguably, the
-     * XXX Redisplay status flag should be cleared regardless
-     * XXX of any concern but that {window} is a valid pointer
-     * XXX (which this function is assuming anyway).
-     * XXX Especially since old GLUT wouldn't even enter its main
-     * XXX loop if you didn't have a display callback defined...
-     */
-    if( ( FETCH_WCB( *window, Display ) ) &&
-        window->State.Redisplay &&
+    if( window->State.Redisplay &&
         window->State.Visible )
     {
         if( window->State.NeedToResize )
@@ -314,38 +277,20 @@ static void fghCheckJoystickPolls( void )
 static void fghCheckTimers( void )
 {
     long checkTime = fgElapsedTime( );
-    SFG_Timer *timer, *next;
-    SFG_List timedOut;
-
-    fgListInit(&timedOut);
+    SFG_Timer *timer;
 
-    for( timer = (SFG_Timer *)fgState.Timers.First;
-         timer;
-         timer = (SFG_Timer *)next )
+    while( timer = fgState.Timers.First )
     {
-        next = (SFG_Timer *)timer->Node.Next;
+        if( timer->TriggerTime > checkTime )
+            break;
 
-        if( timer->TriggerTime <= checkTime )
-        {
-            fgListRemove( &fgState.Timers, &timer->Node );
-            fgListAppend( &timedOut, &timer->Node );
-        }
-    }
+        fgListRemove( &fgState.Timers, &timer->Node );
+        fgListAppend( &fgState.FreeTimers, &timer->Node );
 
-    /*
-     * Now feel free to execute all the hooked and timed out timer callbacks
-     * And delete the timed out timers...
-     */
-    while ( (timer = (SFG_Timer *)timedOut.First) )
-    {
-        if( timer->Callback != NULL )
-            timer->Callback( timer->ID );
-        fgListRemove( &timedOut, &timer->Node );
-        free( timer );
+        timer->Callback( timer->ID );
     }
 }
 
-
 /*
  * Elapsed Time
  */
@@ -356,12 +301,12 @@ long fgElapsedTime( void )
 #if TARGET_HOST_UNIX_X11
         struct timeval now;
         long elapsed;
-        
+
         gettimeofday( &now, NULL );
-        
+
         elapsed = (now.tv_usec - fgState.Time.Value.tv_usec) / 1000;
         elapsed += (now.tv_sec - fgState.Time.Value.tv_sec) * 1000;
-        
+
         return elapsed;
 #elif TARGET_HOST_WIN32
         return timeGetTime() - fgState.Time.Value;
@@ -473,27 +418,15 @@ static int fgHavePendingRedisplays (void)
     return !!enumerator.data;
 }
 /*
- * Indicates whether there are any outstanding timers.
- */
-#if 0 /* Not used */
-static int fgHaveTimers( void )
-{
-    return !!fgState.Timers.First;
-}
-#endif
-/*
  * Returns the number of GLUT ticks (milliseconds) till the next timer event.
  */
 static long fgNextTimer( void )
 {
-    long now = fgElapsedTime();
     long ret = INT_MAX;
     SFG_Timer *timer;
 
-    for( timer = (SFG_Timer *)fgState.Timers.First;
-         timer;
-         timer = (SFG_Timer *)timer->Node.Next )
-        ret = MIN( ret, MAX( 0, timer->TriggerTime - now ) );
+    if( (timer = fgState.Timers.First) )
+        ret = timer->TriggerTime - fgElapsedTime();
 
     return ret;
 }
@@ -590,8 +523,16 @@ void FGAPIENTRY glutMainLoopEvent( void )
             {
                 GETWINDOW( xclient ); 
 
-                fgCloseWindow ( window );
-                fgAddToWindowDestroyList ( window, GL_FALSE );
+                fgDestroyWindow ( window );
+
+                if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
+                {
+                    fgDeinitialize( );
+                    exit( 0 );
+                }
+
+                fgState.ExecState = GLUT_EXEC_STATE_STOP;
+                return;
             }
             break;
 
@@ -621,7 +562,7 @@ void FGAPIENTRY glutMainLoopEvent( void )
              * This is sent to confirm the XDestroyWindow call.
              * XXX WHY is this commented out?  Should we re-enable it?
              */
-            /* fgAddToWindowDestroyList ( window, GL_FALSE ); */
+            /* fgAddToWindowDestroyList ( window ); */
             break;
 
         case Expose:
@@ -851,9 +792,6 @@ void FGAPIENTRY glutMainLoopEvent( void )
                 ! FETCH_WCB( *window, MouseWheel ) )
                 break;
 
-            /*
-             * XXX Why don't we use {window}?  Other code here does...
-             */
             fgState.Modifiers = fgGetXModifiers( &event );
 
             /*
@@ -1028,14 +966,23 @@ void FGAPIENTRY glutMainLoopEvent( void )
     while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) )
     {
         if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 )
-            fgState.ExecState = GLUT_EXEC_STATE_STOP ;
+        {
+            if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
+            {
+                fgDeinitialize( );
+                exit( 0 );
+            }
+            fgState.ExecState = GLUT_EXEC_STATE_STOP;
+            return;
+        }
 
         TranslateMessage( &stMsg );
         DispatchMessage( &stMsg );
     }
 #endif
 
-    fghCheckTimers( );
+    if( fgState.Timers.First )
+        fghCheckTimers( );
     fghCheckJoystickPolls( );
     fghDisplayAll( );
 
@@ -1094,18 +1041,11 @@ void FGAPIENTRY glutMainLoop( void )
         }
     }
 
-    {
-        fgExecutionState execState = fgState.ExecState;
-        
-        /*
-         * When this loop terminates, destroy the display, state and structure
-         * of a freeglut session, so that another glutInit() call can happen
-         */
-        fgDeinitialize( );
-
-        if( execState == GLUT_ACTION_EXIT )
-            exit( 0 );
-    }
+    /*
+     * When this loop terminates, destroy the display, state and structure
+     * of a freeglut session, so that another glutInit() call can happen
+     */
+    fgDeinitialize( );
 }
 
 /*
@@ -1288,38 +1228,9 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
         break;
 
     case WM_CLOSE:
-        /*
-         * Make sure we don't close a window with current context active
-         */
-        if( fgStructure.Window == window )
-        {
-            int used = FALSE ;
-            SFG_Window *iter ;
-
-            wglMakeCurrent( NULL, NULL );
-            /*
-             * Step through the list of windows.  If the rendering context
-             * is not being used by another window, then we delete it.
-             */
-            for( iter = (SFG_Window *)fgStructure.Windows.First;
-                 iter;
-                 iter = (SFG_Window *)iter->Node.Next )
-            {
-                if( ( iter->Window.Context == window->Window.Context ) &&
-                    ( iter != window ) )
-                    used = TRUE;
-            }
-
-            if( ! used )
-                wglDeleteContext( window->Window.Context );
-        }
-
-        /*
-         * Put on a linked list of windows to be removed after all the
-         * callbacks have returned
-         */
-        fgAddToWindowDestroyList( window, GL_FALSE );
-        DestroyWindow( hWnd );
+        fgDestroyWindow ( window );
+        if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
+            PostQuitMessage(0);
         break;
 
     case WM_DESTROY:
@@ -1719,21 +1630,12 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
         if( fgState.IgnoreKeyRepeat && (lParam & KF_REPEAT) )
             break;
 
-        /*
-         * XXX INVOKE_WCB() takes care of the callback-pointer check.
-         * XXX We could just uncoditionally find/trash the Modifiers
-         * XXX and get rid of the "if( ... ) {" and "}".  Unconditinal
-         * XXX code is simpler code.  (^&
-         */
-        if( FETCH_WCB( *window, Keyboard ) )
-        {
-            fgState.Modifiers = fgGetWin32Modifiers( );
-            INVOKE_WCB( *window, Keyboard,
-                        ( (char)wParam,
-                          window->State.MouseX, window->State.MouseY )
-            );
-            fgState.Modifiers = 0xffffffff;
-        }
+        fgState.Modifiers = fgGetWin32Modifiers( );
+        INVOKE_WCB( *window, Keyboard,
+                    ( (char)wParam,
+                      window->State.MouseX, window->State.MouseY )
+        );
+        fgState.Modifiers = 0xffffffff;
     }
     break;