should not strip out GLUT_DISPLAY_CALLBACK at the end of processing work. It kills...
[freeglut] / src / fg_main.c
index d2108e7..fb3d9db 100644 (file)
@@ -60,7 +60,9 @@ extern void fgPlatformSleepForEvents( fg_time_t msec );
 extern void fgPlatformProcessSingleEvent ( void );
 extern void fgPlatformMainLoopPreliminaryWork ( void );
 
-
+extern void fgPlatformInitWork(SFG_Window* window);
+extern void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask);
+extern void fgPlatformVisibilityWork(SFG_Window* window);
 
 
 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
@@ -92,7 +94,7 @@ void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean for
          * window.
          * DN: Hmm.. the above sounds like a concern only in single buffered mode...
          */
-        glutPostRedisplay( );
+        window->State.WorkMask |= GLUT_DISPLAY_WORK;
         if( window->IsMenu )
             fgSetWindow( saved_window );
     }
@@ -179,33 +181,6 @@ static void fghProcessWork( void )
     fgEnumWindows( fghcbProcessWork, &enumerator );
 }
 
-
-static void fghcbDisplayWindow( SFG_Window *window,
-                                SFG_Enumerator *enumerator )
-{
-    if( window->State.Redisplay &&
-        window->State.Visible )
-    {
-        window->State.Redisplay = GL_FALSE;
-               fghRedrawWindow ( window );
-    }
-
-    fgEnumSubWindows( window, fghcbDisplayWindow, enumerator );
-}
-
-/*
- * Make all windows perform a display call
- */
-static void fghDisplayAll( void )
-{
-    SFG_Enumerator enumerator;
-
-    enumerator.found = GL_FALSE;
-    enumerator.data  =  NULL;
-
-    fgEnumWindows( fghcbDisplayWindow, &enumerator );
-}
-
 /*
  * Window enumerator callback to check for the joystick polling code
  */
@@ -261,7 +236,7 @@ static void fghCheckTimers( void )
         SFG_Timer *timer = fgState.Timers.First;
 
         if( timer->TriggerTime > checkTime )
-            /* XXX: are timers always sorted by triggerTime? If not, this and fghNextTimer are wrong */
+            /* Timers are sorted by triggerTime */
             break;
 
         fgListRemove( &fgState.Timers, &timer->Node );
@@ -357,29 +332,28 @@ void fgWarning( const char *fmt, ... )
 
 
 /*
- * Indicates whether a redisplay is pending for ANY window.
+ * Indicates whether work is pending for ANY window.
  *
  * The current mechanism is to walk all of the windows and ask if
- * a redisplay is pending. We have a short-circuit early
- * return if we find any.
+ * work is pending. We have a short-circuit early return if we find any.
  */
-static void fghHavePendingRedisplaysCallback( SFG_Window* w, SFG_Enumerator* e)
+static void fghHavePendingWorkCallback( SFG_Window* w, SFG_Enumerator* e)
 {
-    if( w->State.Redisplay && w->State.Visible )
+    if( w->State.WorkMask )
     {
         e->found = GL_TRUE;
         e->data = w;
         return;
     }
-    fgEnumSubWindows( w, fghHavePendingRedisplaysCallback, e );
+    fgEnumSubWindows( w, fghHavePendingWorkCallback, e );
 }
-static int fghHavePendingRedisplays (void)
+static int fghHavePendingWork (void)
 {
     SFG_Enumerator enumerator;
 
     enumerator.found = GL_FALSE;
     enumerator.data = NULL;
-    fgEnumWindows( fghHavePendingRedisplaysCallback, &enumerator );
+    fgEnumWindows( fghHavePendingWorkCallback, &enumerator );
     return !!enumerator.data;
 }
 
@@ -388,12 +362,13 @@ static int fghHavePendingRedisplays (void)
  */
 static fg_time_t fghNextTimer( void )
 {
-    fg_time_t currentTime = fgElapsedTime();
-    SFG_Timer *timer = fgState.Timers.First;
+    fg_time_t currentTime;
+    SFG_Timer *timer = fgState.Timers.First;    /* timers are sorted by trigger time, so only have to check the first */
 
     if( !timer )
         return INT_MAX;
 
+    currentTime = fgElapsedTime();
     if( timer->TriggerTime < currentTime )
         return 0;
     else
@@ -404,7 +379,7 @@ static void fghSleepForEvents( void )
 {
     fg_time_t msec;
 
-    if( fghHavePendingRedisplays( ) )
+    if( fghHavePendingWork( ) )
         return;
 
     msec = fghNextTimer( );
@@ -417,6 +392,54 @@ static void fghSleepForEvents( void )
 }
 
 
+/* Step through the work list */
+void fgPlatformProcessWork(SFG_Window *window)
+{
+    unsigned int workMask = window->State.WorkMask;
+    /* Now clear it so that any callback generated by the actions below can set work again */
+    window->State.WorkMask = 0;
+
+    if (workMask&~GLUT_DISPLAY_WORK)    /* Display work is the common case, skip all the below at once */
+    {
+        if (workMask & GLUT_INIT_WORK)
+        {
+            /* This is before the first display callback: if needed for the platform,
+             * call a few callbacks to inform user of window size, position, etc
+             */
+            fgPlatformInitWork(window);
+
+            /* Call init context callback */
+            INVOKE_WCB( *window, InitContext, ());
+
+            /* Lastly, check if we have a display callback, error out if not
+             * This is the right place to do it, as the redisplay will be
+             * next right after we exit this function, so there is no more
+             * opportunity for the user to register a callback for this window.
+             */
+            if (!FETCH_WCB(*window, Display))
+                fgError ( "ERROR:  No display callback registered for window %d\n", window->ID );
+        }
+
+        /* On windows we can position, resize and change z order at the same time */
+        if (workMask & (GLUT_POSITION_WORK|GLUT_SIZE_WORK|GLUT_ZORDER_WORK|GLUT_FULL_SCREEN_WORK))
+        {
+            fgPlatformPosResZordWork(window,workMask);
+        }
+
+        if (workMask & GLUT_VISIBILITY_WORK)
+        {
+            fgPlatformVisibilityWork(window);
+        }
+    }
+
+    if (workMask & GLUT_DISPLAY_WORK)
+    {
+        if( window->State.Visible )
+            fghRedrawWindow ( window );
+    }
+}
+
+
 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
 
 /*
@@ -432,12 +455,9 @@ void FGAPIENTRY glutMainLoopEvent( void )
     if (fgState.NumActiveJoysticks>0)   /* If zero, don't poll joysticks */
         fghCheckJoystickPolls( );
 
-    /* Perform work on the window (position, reshape, etc) */
+    /* Perform work on the window (position, reshape, display, etc) */
     fghProcessWork( );
 
-    /* Display */
-    fghDisplayAll( );
-
     fgCloseWindows( );
 }