X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ffreeglut_main.c;h=6375448cc1d5c31aee70f063f7633135ce3ad8a0;hb=02d1360233aa5a71d0f46fda6c6956c5122fad80;hp=e5b7c508c5ca4438ba51e71409a1065716fcee85;hpb=4cba0748bb698d485cdad359b28ae4b2c6acc362;p=freeglut diff --git a/src/freeglut_main.c b/src/freeglut_main.c index e5b7c50..6375448 100644 --- a/src/freeglut_main.c +++ b/src/freeglut_main.c @@ -87,54 +87,65 @@ static void fghReshapeWindowByHandle ( SFG_WindowHandleType handle, #elif TARGET_HOST_WIN32 { - RECT winRect; - int x, y; + RECT rect; - GetWindowRect( window->Window.Handle, &winRect ); - x = winRect.left; - y = winRect.top; + /* + * For windowed mode, get the current position of the + * window and resize taking the size of the frame + * decorations into account. + */ + + GetWindowRect( window->Window.Handle, &rect ); + rect.right = rect.left + width; + rect.bottom = rect.top + height; if ( window->Parent == NULL ) { - /* - * Adjust the size of the window to allow for the size of the - * frame, if we are not a menu - */ - if ( ! window->IsMenu ) + if ( ! window->IsMenu && !window->State.IsGameMode ) { - width += GetSystemMetrics( SM_CXSIZEFRAME ) * 2; - height += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + - GetSystemMetrics( SM_CYCAPTION ); + rect.right += GetSystemMetrics( SM_CXSIZEFRAME ) * 2; + rect.bottom += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + + GetSystemMetrics( SM_CYCAPTION ); } } else { - GetWindowRect( window->Parent->Window.Handle, - &winRect ); - x -= winRect.left + GetSystemMetrics( SM_CXSIZEFRAME ); - y -= winRect.top + GetSystemMetrics( SM_CYSIZEFRAME ) + - GetSystemMetrics( SM_CYCAPTION ); + GetWindowRect( window->Parent->Window.Handle, &rect ); + AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | + WS_CLIPCHILDREN, FALSE ); } - MoveWindow( - window->Window.Handle, - x, - y, - width, - height, - TRUE + /* + * SWP_NOACTIVATE Do not activate the window + * SWP_NOOWNERZORDER Do not change position in z-order + * SWP_NOSENDCHANGING Supress WM_WINDOWPOSCHANGING message + * SWP_NOZORDER Retains the current Z order (ignore 2nd param) + */ + + SetWindowPos( window->Window.Handle, + HWND_TOP, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | + SWP_NOZORDER ); } -#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 @@ -188,25 +199,25 @@ static void fghRedrawWindowByHandle ( SFG_WindowHandleType handle ) static void fghcbDisplayWindow( SFG_Window *window, SFG_Enumerator *enumerator ) { + if( window->State.NeedToResize ) + { + SFG_Window *current_window = fgStructure.Window; + + fgSetWindow( window ); + + fghReshapeWindowByHandle( + window->Window.Handle, + window->State.Width, + window->State.Height + ); + + window->State.NeedToResize = GL_FALSE; + fgSetWindow( current_window ); + } + if( window->State.Redisplay && window->State.Visible ) { - if( window->State.NeedToResize ) - { - SFG_Window *current_window = fgStructure.Window; - - fgSetWindow( window ); - - fghReshapeWindowByHandle( - window->Window.Handle, - window->State.Width, - window->State.Height - ); - - window->State.NeedToResize = GL_FALSE; - fgSetWindow ( current_window ); - } - window->State.Redisplay = GL_FALSE; #if TARGET_HOST_UNIX_X11 @@ -277,38 +288,21 @@ static void fghCheckJoystickPolls( void ) static void fghCheckTimers( void ) { long checkTime = fgElapsedTime( ); - SFG_Timer *timer, *next; - SFG_List timedOut; - fgListInit(&timedOut); - - for( timer = (SFG_Timer *)fgState.Timers.First; - timer; - timer = (SFG_Timer *)next ) + while( fgState.Timers.First ) { - next = (SFG_Timer *)timer->Node.Next; + SFG_Timer *timer = fgState.Timers.First; - if( timer->TriggerTime <= checkTime ) - { - fgListRemove( &fgState.Timers, &timer->Node ); - fgListAppend( &timedOut, &timer->Node ); - } - } + if( timer->TriggerTime > checkTime ) + break; - /* - * 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 ); + fgListRemove( &fgState.Timers, &timer->Node ); + fgListAppend( &fgState.FreeTimers, &timer->Node ); + + timer->Callback( timer->ID ); } } - /* * Elapsed Time */ @@ -319,12 +313,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; @@ -436,27 +430,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; } @@ -482,7 +466,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 ); @@ -553,8 +537,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; @@ -564,19 +556,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: @@ -584,16 +595,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 ); @@ -618,6 +634,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 ); @@ -685,7 +704,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 ) @@ -755,7 +776,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 ) ) @@ -782,12 +803,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; } @@ -800,6 +828,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 ); @@ -819,7 +850,7 @@ void FGAPIENTRY glutMainLoopEvent( void ) /* * 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, @@ -988,14 +1019,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( ); @@ -1041,31 +1081,37 @@ void FGAPIENTRY glutMainLoop( void ) fgState.ExecState = GLUT_EXEC_STATE_RUNNING ; while( fgState.ExecState == GLUT_EXEC_STATE_RUNNING ) { - glutMainLoopEvent( ); + SFG_Window *window; - if( fgStructure.Windows.First == NULL ) + glutMainLoopEvent( ); + /* + * Step through the list of windows, seeing if there are any + * that are not menus + */ + for( window = ( SFG_Window * )fgStructure.Windows.First; + window; + window = ( SFG_Window * )window->Node.Next ) + if ( ! ( window->IsMenu ) ) + break; + + if( ! window ) fgState.ExecState = GLUT_EXEC_STATE_STOP; else { if( fgState.IdleCallback ) fgState.IdleCallback( ); - fgSleepForEvents(); + fgSleepForEvents( ); } } - { - 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( ); + if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) + exit( 0 ); } /* @@ -1248,38 +1294,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: @@ -1360,11 +1377,14 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, break; } - if( GetSystemMetrics( SM_SWAPBUTTON ) ) - if( button == GLUT_LEFT_BUTTON ) + if ( GetSystemMetrics( SM_SWAPBUTTON ) ) + { + if ( button == GLUT_LEFT_BUTTON ) button = GLUT_RIGHT_BUTTON; - else if( button == GLUT_RIGHT_BUTTON ) + else + if ( button == GLUT_RIGHT_BUTTON ) button = GLUT_LEFT_BUTTON; + } if( button == -1 ) return DefWindowProc( hWnd, uMsg, lParam, wParam ); @@ -1429,7 +1449,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 );