X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ffreeglut_main.c;h=5fbce0c7ee3053cceffc5527fd695bff8191fb70;hb=5800cecd9ce89911e948c2e0abc982bfb5e8b675;hp=6413363df055a8f07593d8382de70c4abebbf0d0;hpb=a5e39e2546cb979ef5a224a808229f27963537c7;p=freeglut diff --git a/src/freeglut_main.c b/src/freeglut_main.c index 6413363..5fbce0c 100644 --- a/src/freeglut_main.c +++ b/src/freeglut_main.c @@ -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 @@ -138,15 +126,19 @@ static void fghReshapeWindowByHandle ( SFG_WindowHandleType handle, ); } -#endif - - if( !( FETCH_WCB( *window, Reshape ) ) ) + /* + * XXX Should update {window->State.OldWidth, window->State.OldHeight} + * XXX to keep in lockstep with UNIX_X11 code. + */ + if( FETCH_WCB( *window, Reshape ) ) + INVOKE_WCB( *window, Reshape, ( width, height ) ); + else { fgSetWindow( window ); glViewport( 0, 0, width, height ); } - else - INVOKE_WCB( *window, Reshape, ( width, height ) ); + +#endif /* * Force a window redraw. In Windows at least this is only a partial @@ -168,25 +160,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 +183,6 @@ static void fghRedrawWindowByHandle ( SFG_WindowHandleType handle ) fgSetWindow ( current_window ); } - window->State.Redisplay = GL_FALSE; INVOKE_WCB( *window, Display, ( ) ); } @@ -215,19 +192,24 @@ 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 ) { + /* + * XXX Resizing should *not* depend upon whether there + * XXX is a pending redisplay flag, as far as I can tell. + * XXX + * XXX Note, too, that the {NeedToResize} flag is a little + * XXX fuzzy in its meaning, since for WIN32, this also + * XXX means "we need to tell the application that the window has + * XXX changed size", while in X11, it only means "we need + * XXX to ask the window system to resize the window. + * XXX Splitting the flag's meaning might be desirable, but + * XXX that could complicate the code more. (On X11, the + * XXX user callback is called as soon as the event is + * XXX discovered, but resizing the window is postponed + * XXX until after other events.) + */ if( window->State.NeedToResize ) { SFG_Window *current_window = fgStructure.Window; @@ -314,38 +296,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 +320,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 +437,17 @@ 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; + SFG_Timer *timer = fgState.Timers.First; - for( timer = (SFG_Timer *)fgState.Timers.First; - timer; - timer = (SFG_Timer *)timer->Node.Next ) - ret = MIN( ret, MAX( 0, timer->TriggerTime - now ) ); + if( timer ) + ret = timer->TriggerTime - fgElapsedTime(); + if( ret < 0 ) + ret = 0; return ret; } @@ -519,7 +473,7 @@ static void fgSleepForEvents( void ) msec = fgNextTimer( ); if( fgHaveJoystick( ) ) msec = MIN( msec, 10 ); - + wait.tv_sec = msec / 1000; wait.tv_usec = (msec % 1000) * 1000; err = select( socket+1, &fdset, NULL, NULL, &wait ); @@ -590,8 +544,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; @@ -601,19 +563,38 @@ void FGAPIENTRY glutMainLoopEvent( void ) * (in freeglut only) will not get an initial reshape event, * which can break things. * - * XXX NOTE that it is possible that you will more than one Reshape - * XXX event for your top-level window, but something like this - * XXX appears to be required for compatbility. - * * GLUT presumably does this because it generally tries to treat * sub-windows the same as windows. + * + * XXX Technically, GETWINDOW( xconfigure ) and + * XXX {event.xconfigure} may not be legit ways to get at + * XXX data for CreateNotify events. In practice, the data + * XXX is in a union which is laid out much the same either + * XXX way. But if you want to split hairs, this isn't legit, + * XXX and we should instead duplicate some code. */ case CreateNotify: case ConfigureNotify: GETWINDOW( xconfigure ); - window->State.NeedToResize = GL_TRUE ; - window->State.Width = event.xconfigure.width ; - window->State.Height = event.xconfigure.height; + { + int width = event.xconfigure.width; + int height = event.xconfigure.height; + + if( ( width != window->State.OldWidth ) || + ( height != window->State.OldHeight ) ) + { + window->State.OldWidth = width; + window->State.OldHeight = height; + if( FETCH_WCB( *window, Reshape ) ) + INVOKE_WCB( *window, Reshape, ( width, height ) ); + else + { + fgSetWindow( window ); + glViewport( 0, 0, width, height ); + } + glutPostRedisplay( ); + } + } break; case DestroyNotify: @@ -621,16 +602,21 @@ 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: /* * We are too dumb to process partial exposes... + * * XXX Well, we could do it. However, it seems to only * XXX be potentially useful for single-buffered (since * XXX double-buffered does not respect viewport when we * XXX do a buffer-swap). + * + * XXX GETWINDOW( xexpose ); + * XXX fgSetWindow( window ); + * XXX glutPostRedisplay( ); */ if( event.xexpose.count == 0 ) fghRedrawWindowByHandle( event.xexpose.window ); @@ -655,6 +641,9 @@ void FGAPIENTRY glutMainLoopEvent( void ) case VisibilityNotify: { GETWINDOW( xvisibility ); + /* + * XXX INVOKE_WCB() does this check for us. + */ if( ! FETCH_WCB( *window, WindowStatus ) ) break; fgSetWindow( window ); @@ -722,7 +711,9 @@ void FGAPIENTRY glutMainLoopEvent( void ) /* * XXX For more than 5 buttons, just check {event.xmotion.state}, - * XXX rather than a host of bit-masks? + * XXX rather than a host of bit-masks? Or maybe we need to + * XXX track ButtonPress/ButtonRelease events in our own + * XXX bit-mask? */ #define BUTTON_MASK \ ( Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) @@ -792,7 +783,7 @@ void FGAPIENTRY glutMainLoopEvent( void ) window->ActiveMenu->Window->State.MouseY = event.xbutton.y_root - window->ActiveMenu->Y; } - + /* In the menu, invoke the callback and deactivate the menu*/ if( fgCheckActiveMenu( window->ActiveMenu->Window, window->ActiveMenu ) ) @@ -819,12 +810,19 @@ void FGAPIENTRY glutMainLoopEvent( void ) else if( pressed ) /* * Outside the menu, deactivate if it's a downclick + * * XXX This isn't enough. A downclick outside of * XXX the interior of our freeglut windows should also * XXX deactivate the menu. This is more complicated. */ fgDeactivateMenu( window->ActiveMenu->ParentWindow ); - + + /* + * XXX Why does an active menu require a redisplay at + * XXX this point? If this can come out cleanly, then + * XXX it probably should do so; if not, a comment should + * XXX explain it. + */ window->State.Redisplay = GL_TRUE; break; } @@ -837,6 +835,9 @@ void FGAPIENTRY glutMainLoopEvent( void ) ( window->Menu[ button ] ) && pressed ) { + /* + * XXX Posting a requisite Redisplay seems bogus. + */ window->State.Redisplay = GL_TRUE; fgSetWindow( window ); fgActivateMenu( window, button ); @@ -851,15 +852,12 @@ void FGAPIENTRY glutMainLoopEvent( void ) ! FETCH_WCB( *window, MouseWheel ) ) break; - /* - * XXX Why don't we use {window}? Other code here does... - */ fgState.Modifiers = fgGetXModifiers( &event ); /* * Finally execute the mouse or mouse wheel callback * - * XXX Use a symbolic constant, *not* "4"! + * XXX Use a symbolic constant, *not* "4"! ("3, sire!") */ if( ( button < 3 ) || ( ! FETCH_WCB( *window, MouseWheel ) ) ) INVOKE_WCB( *window, Mouse, ( button, @@ -1028,14 +1026,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 +1101,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 +1288,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: @@ -1469,7 +1440,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, break; } - if ( window->Menu[ button ] && pressed ) + if( window->Menu[ button ] && pressed ) { window->State.Redisplay = GL_TRUE; fgSetWindow( window ); @@ -1719,21 +1690,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;