X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ffg_main.c;h=4dee9b9948c71ae726e2f0cdcc6082472db05c31;hb=a00c7ee3552b527ac6b375d6a6ca42f90770ddc3;hp=fd94e0efd0b747e1884c3e72013865df68bfb2fc;hpb=f50219f3ee035143ce9a056e4362959bef5c91cc;p=freeglut diff --git a/src/fg_main.c b/src/fg_main.c index fd94e0e..4dee9b9 100644 --- a/src/fg_main.c +++ b/src/fg_main.c @@ -54,8 +54,7 @@ # define MIN(a,b) (((a)<(b)) ? (a) : (b)) #endif -extern void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height ); -extern void fgPlatformDisplayWindow ( SFG_Window *window ); +extern void fgPlatformProcessWork ( SFG_Window *window ); extern fg_time_t fgPlatformSystemTime ( void ); extern void fgPlatformSleepForEvents( fg_time_t msec ); extern void fgPlatformProcessSingleEvent ( void ); @@ -66,104 +65,118 @@ extern void fgPlatformMainLoopPreliminaryWork ( void ); /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ -static void fghReshapeWindow ( SFG_Window *window, int width, int height ) +void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify) { - SFG_Window *current_window = fgStructure.CurrentWindow; + GLboolean notify = GL_FALSE; - freeglut_return_if_fail( window != NULL ); + if( width != window->State.Width || + height != window->State.Height ) + { + window->State.Width = width; + window->State.Height = height; - fgPlatformReshapeWindow ( window, width, height ); + notify = GL_TRUE; + } - if( FETCH_WCB( *window, Reshape ) ) - INVOKE_WCB( *window, Reshape, ( width, height ) ); - else + if (notify || forceNotify) { - fgSetWindow( window ); - glViewport( 0, 0, width, height ); + SFG_Window *saved_window = fgStructure.CurrentWindow; + + INVOKE_WCB( *window, Reshape, ( width, height ) ); + + /* + * Force a window redraw. In Windows at least this is only a partial + * solution: if the window is increasing in size in either dimension, + * the already-drawn part does not get drawn again and things look funny. + * But without this we get this bad behaviour whenever we resize the + * window. + * DN: Hmm.. the above sounds like a concern only in single buffered mode... + */ + window->State.WorkMask |= GLUT_DISPLAY_WORK; + if( window->IsMenu ) + fgSetWindow( saved_window ); } +} - /* - * Force a window redraw. In Windows at least this is only a partial - * solution: if the window is increasing in size in either dimension, - * the already-drawn part does not get drawn again and things look funny. - * But without this we get this bad behaviour whenever we resize the - * window. - * DN: Hmm.. the above sounds like a concern only in single buffered mode... - */ - window->State.Redisplay = GL_TRUE; +void fghOnPositionNotify(SFG_Window *window, int x, int y, GLboolean forceNotify) +{ + GLboolean notify = GL_FALSE; + + if( x != window->State.Xpos || + y != window->State.Ypos ) + { + window->State.Xpos = x; + window->State.Ypos = y; - if( window->IsMenu ) - fgSetWindow( current_window ); + notify = GL_TRUE; + } + + if (notify || forceNotify) + { + SFG_Window *saved_window = fgStructure.CurrentWindow; + INVOKE_WCB( *window, Position, ( x, y ) ); + fgSetWindow( saved_window ); + } } /* * Calls a window's redraw method. This is used when - * a redraw is forced by the incoming window messages. + * a redraw is forced by the incoming window messages, + * or if a redisplay is otherwise pending. + * this is lean and mean without checks as it is + * currently only called from fghcbDisplayWindow which + * only calls this if the window is visible and needs + * a redisplay. + * Note that the fgSetWindow call on Windows makes the + * right device context current on windows, allowing + * direct drawing without BeginPaint/EndPaint in the + * WM_PAINT handler. */ void fghRedrawWindow ( SFG_Window *window ) { SFG_Window *current_window = fgStructure.CurrentWindow; - freeglut_return_if_fail( window ); - - if( window->State.NeedToInitContext ) { - INVOKE_WCB( *window, InitContext, ()); - window->State.NeedToInitContext = GL_FALSE; - } - - freeglut_return_if_fail( FETCH_WCB ( *window, Display ) ); + fgSetWindow( window ); + INVOKE_WCB( *window, Display, ( ) ); - window->State.Redisplay = GL_FALSE; + fgSetWindow( current_window ); +} - freeglut_return_if_fail( window->State.Visible ); +void fghRedrawWindowAndChildren ( SFG_Window *window ) +{ + SFG_Window* child; - fgSetWindow( window ); + fghRedrawWindow(window); - if( window->State.NeedToResize ) + for( child = ( SFG_Window * )window->Children.First; + child; + child = ( SFG_Window * )child->Node.Next ) { - /* Set need to resize to false before calling fghReshapeWindow, otherwise - in the case the user's reshape callback calls glutReshapeWindow, - his request would get canceled after fghReshapeWindow gets called. - */ - window->State.NeedToResize = GL_FALSE; - - fghReshapeWindow( - window, - window->State.Width, - window->State.Height - ); + fghRedrawWindowAndChildren(child); } - - INVOKE_WCB( *window, Display, ( ) ); - - fgSetWindow( current_window ); } -static void fghcbDisplayWindow( SFG_Window *window, - SFG_Enumerator *enumerator ) +static void fghcbProcessWork( SFG_Window *window, + SFG_Enumerator *enumerator ) { - if( window->State.Redisplay && - window->State.Visible ) - { - window->State.Redisplay = GL_FALSE; - fgPlatformDisplayWindow ( window ); - } + if( window->State.WorkMask ) + fgPlatformProcessWork ( window ); - fgEnumSubWindows( window, fghcbDisplayWindow, enumerator ); + fgEnumSubWindows( window, fghcbProcessWork, enumerator ); } /* - * Make all windows perform a display call + * Make all windows process their work list */ -static void fghDisplayAll( void ) +static void fghProcessWork( void ) { SFG_Enumerator enumerator; enumerator.found = GL_FALSE; enumerator.data = NULL; - fgEnumWindows( fghcbDisplayWindow, &enumerator ); + fgEnumWindows( fghcbProcessWork, &enumerator ); } /* @@ -221,6 +234,7 @@ static void fghCheckTimers( void ) SFG_Timer *timer = fgState.Timers.First; if( timer->TriggerTime > checkTime ) + /* Timers are sorted by triggerTime */ break; fgListRemove( &fgState.Timers, &timer->Node ); @@ -267,7 +281,7 @@ void fgError( const char *fmt, ... ) va_end( ap ); } else { -#if FREEGLUT_ERRORS +#ifdef FREEGLUT_PRINT_ERRORS va_start( ap, fmt ); fprintf( stderr, "freeglut "); @@ -300,7 +314,7 @@ void fgWarning( const char *fmt, ... ) va_end( ap ); } else { -#if FREEGLUT_WARNINGS +#ifdef FREEGLUT_PRINT_WARNINGS va_start( ap, fmt ); fprintf( stderr, "freeglut "); @@ -316,30 +330,28 @@ void fgWarning( const char *fmt, ... ) /* - * Indicates whether Joystick events are being used by ANY window. + * Indicates whether work is pending for ANY window. * * The current mechanism is to walk all of the windows and ask if - * there is a joystick callback. We have a short-circuit early - * return if we find any joystick handler registered. - * - * + * 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; } @@ -348,12 +360,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 @@ -364,7 +377,7 @@ static void fghSleepForEvents( void ) { fg_time_t msec; - if( fghHavePendingRedisplays( ) ) + if( fghHavePendingWork( ) ) return; msec = fghNextTimer( ); @@ -384,13 +397,16 @@ static void fghSleepForEvents( void ) */ void FGAPIENTRY glutMainLoopEvent( void ) { + /* Process input */ fgPlatformProcessSingleEvent (); if( fgState.Timers.First ) fghCheckTimers( ); if (fgState.NumActiveJoysticks>0) /* If zero, don't poll joysticks */ fghCheckJoystickPolls( ); - fghDisplayAll( ); + + /* Perform work on the window (position, reshape, display, etc) */ + fghProcessWork( ); fgCloseWindows( ); }