X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ffreeglut_main.c;h=fb756545f9e42b5991f3b579373c2aaef8837e97;hb=d6ccf7c81bdad11e6902a258e8e21fdbe6b9f968;hp=3982d4b4b26e14ac0037d7d87ba66300bc3e5d31;hpb=5d724da03c1b5988304888c17c5eba8a40c0a529;p=freeglut diff --git a/src/freeglut_main.c b/src/freeglut_main.c index 3982d4b..fb75654 100644 --- a/src/freeglut_main.c +++ b/src/freeglut_main.c @@ -29,7 +29,7 @@ #include "config.h" #endif -#include "../include/GL/freeglut.h" +#include #include "freeglut_internal.h" #include @@ -65,64 +65,87 @@ /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ /* - * Calls a window's redraw method. This is used when - * a redraw is forced by the incoming window messages. - * - * XXX We can/should make a "unified" window handle type so that - * XXX the function headers don't need this silly #ifdef junk. - * XXX Make the type, say, {fgWindow}. On UNIX_X11, this is - * XXX {Window}. On WIN32, it is {HWND}. Then do the #ifdef - * XXX junk *once* in "freeglut_internal.h". - */ -static void fghRedrawWindowByHandle -#if TARGET_HOST_UNIX_X11 - ( Window handle ) -#elif TARGET_HOST_WIN32 - ( HWND handle ) -#endif -{ - SFG_Window* window = fgWindowByHandle( handle ); - freeglut_return_if_fail( window != NULL ); - freeglut_return_if_fail( FETCH_WCB( *window, Display ) ); - freeglut_return_if_fail( window->State.Visible == TRUE ); - - /* fgSetWindow( window ); */ - window->State.Redisplay = FALSE; - /* window->Callbacks.Display( ); */ - INVOKE_WCB( *window, Display, ( ) ); -} - -/* * Handle a window configuration change. When no reshape * callback is hooked, the viewport size is updated to * match the new window size. */ -static void fghReshapeWindowByHandle -#if TARGET_HOST_UNIX_X11 - ( Window handle, int width, int height ) -#elif TARGET_HOST_WIN32 - ( HWND handle, int width, int height ) -#endif +static void fghReshapeWindowByHandle ( SFG_WindowHandleType handle, + int width, int height ) { SFG_Window *current_window = fgStructure.Window; SFG_Window* window = fgWindowByHandle( handle ); freeglut_return_if_fail( window != NULL ); + +#if TARGET_HOST_UNIX_X11 + + XResizeWindow( fgDisplay.Display, window->Window.Handle, + width, height ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_WIN32 + + { + RECT rect; + + /* + * 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 ) + { + if ( ! window->IsMenu && !window->State.IsGameMode ) + { + rect.right += GetSystemMetrics( SM_CXSIZEFRAME ) * 2; + rect.bottom += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + + GetSystemMetrics( SM_CYCAPTION ); + } + } + else + { + GetWindowRect( window->Parent->Window.Handle, &rect ); + AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | + WS_CLIPCHILDREN, FALSE ); + } + + /* + * 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 + ); + } + /* - * fgSetWindow( window ); - * if( window->Callbacks.Reshape != NULL ) - * window->Callbacks.Reshape( width, height ); - * else - * glViewport( 0, 0, width, height ); + * XXX Should update {window->State.OldWidth, window->State.OldHeight} + * XXX to keep in lockstep with UNIX_X11 code. */ - if( !( FETCH_WCB( *window, Reshape ) ) ) + 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 @@ -131,62 +154,86 @@ static void fghReshapeWindowByHandle * But without this we get this bad behaviour whenever we resize the * window. */ - window->State.Redisplay = TRUE; + window->State.Redisplay = GL_TRUE; if( window->IsMenu ) fgSetWindow( current_window ); } /* - * A static helper function to execute display callback for a window + * Calls a window's redraw method. This is used when + * a redraw is forced by the incoming window messages. */ -static void fghcbDisplayWindow( SFG_Window *window, SFG_Enumerator *enumerator ) +static void fghRedrawWindowByHandle ( SFG_WindowHandleType handle ) { -#if TARGET_HOST_UNIX_X11 - if( ( FETCH_WCB( *window, Display ) ) && - ( window->State.Redisplay == TRUE ) && - ( window->State.Visible == TRUE ) ) + SFG_Window* window = fgWindowByHandle( handle ); + freeglut_return_if_fail( window ); + freeglut_return_if_fail( FETCH_WCB ( *window, Display ) ); + + window->State.Redisplay = GL_FALSE; + + freeglut_return_if_fail( window->State.Visible ); + + if( window->State.NeedToResize ) { - SFG_Window *current_window = fgStructure.Window ; + SFG_Window *current_window = fgStructure.Window; - /* fgSetWindow( window ); */ - window->State.Redisplay = FALSE; - /* window->Callbacks.Display( ); */ - INVOKE_WCB( *window, Display, ( ) ); + fgSetWindow( window ); + + fghReshapeWindowByHandle( + window->Window.Handle, + window->State.Width, + window->State.Height + ); + + window->State.NeedToResize = GL_FALSE; fgSetWindow( current_window ); } -#elif TARGET_HOST_WIN32 + INVOKE_WCB( *window, Display, ( ) ); +} +/* + * A static helper function to execute display callback for a window + */ +static void fghcbDisplayWindow( SFG_Window *window, + SFG_Enumerator *enumerator ) +{ if( window->State.NeedToResize ) { SFG_Window *current_window = fgStructure.Window; fgSetWindow( window ); - fghReshapeWindowByHandle( + fghReshapeWindowByHandle( window->Window.Handle, - glutGet( GLUT_WINDOW_WIDTH ), - glutGet( GLUT_WINDOW_HEIGHT ) + window->State.Width, + window->State.Height ); - window->State.NeedToResize = FALSE; + window->State.NeedToResize = GL_FALSE; fgSetWindow ( current_window ); } - if( ( FETCH_WCB( *window, Display ) ) && - ( window->State.Redisplay == TRUE ) && - ( window->State.Visible == TRUE ) ) + if( window->State.Redisplay && + window->State.Visible ) { - window->State.Redisplay = FALSE; + window->State.Redisplay = GL_FALSE; +#if TARGET_HOST_UNIX_X11 + { + SFG_Window *current_window = fgStructure.Window; + + INVOKE_WCB( *window, Display, ( ) ); + fgSetWindow( current_window ); + } +#elif TARGET_HOST_WIN32 RedrawWindow( - window->Window.Handle, NULL, NULL, + window->Window.Handle, NULL, NULL, RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW ); - } - #endif + } fgEnumSubWindows( window, fghcbDisplayWindow, enumerator ); } @@ -198,7 +245,7 @@ static void fghDisplayAll( void ) { SFG_Enumerator enumerator; - enumerator.found = FALSE; + enumerator.found = GL_FALSE; enumerator.data = NULL; fgEnumWindows( fghcbDisplayWindow, &enumerator ); @@ -229,7 +276,7 @@ static void fghCheckJoystickPolls( void ) { SFG_Enumerator enumerator; - enumerator.found = FALSE; + enumerator.found = GL_FALSE; enumerator.data = NULL; fgEnumWindows( fghcbCheckJoystickPolls, &enumerator ); @@ -241,56 +288,53 @@ 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 */ long fgElapsedTime( void ) { + if ( fgState.Time.Set ) + { +#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; +#endif + } + else + { #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; + gettimeofday( &fgState.Time.Value, NULL ); #elif TARGET_HOST_WIN32 - return timeGetTime() - fgState.Time.Value; + fgState.Time.Value = timeGetTime (); #endif + fgState.Time.Set = GL_TRUE ; + + return 0 ; + } } /* @@ -310,6 +354,9 @@ void fgError( const char *fmt, ... ) va_end( ap ); + if ( fgState.Initialised ) + fgDeinitialize (); + exit( 1 ); } @@ -332,27 +379,19 @@ void fgWarning( const char *fmt, ... ) * Indicates whether Joystick events are being used by ANY window. * * The current mechanism is to walk all of the windows and ask if - * there is a joystick callback. Certainly in some cases, maybe - * in all cases, the joystick is attached to the system and accessed - * from ONE point by GLUT/freeglut, so this is not the right way, - * in general, to do this. However, the Joystick code is segregated - * in its own little world, so we can't access the information that - * we need in order to do that nicely. + * there is a joystick callback. We have a short-circuit early + * return if we find any joystick handler registered. * - * Some alternatives: - * * Store Joystick data into freeglut global state. - * * Provide NON-static functions or data from Joystick *.c file. - * - * Basically, the RIGHT way to do this requires knowing something - * about the Joystick. Right now, the Joystick code is behind - * an opaque wall. + * The real way to do this is to make use of the glutTimer() API + * to more cleanly re-implement the joystick API. Then, this code + * and all other "joystick timer" code can be yanked. * */ static void fgCheckJoystickCallback( SFG_Window* w, SFG_Enumerator* e) { if( FETCH_WCB( *w, Joystick ) ) { - e->found = TRUE; + e->found = GL_TRUE; e->data = w; } fgEnumSubWindows( w, fgCheckJoystickCallback, e ); @@ -360,7 +399,7 @@ static void fgCheckJoystickCallback( SFG_Window* w, SFG_Enumerator* e) static int fgHaveJoystick( void ) { SFG_Enumerator enumerator; - enumerator.found = FALSE; + enumerator.found = GL_FALSE; enumerator.data = NULL; fgEnumWindows( fgCheckJoystickCallback, &enumerator ); return !!enumerator.data; @@ -369,39 +408,31 @@ static void fgHavePendingRedisplaysCallback( SFG_Window* w, SFG_Enumerator* e) { if( w->State.Redisplay ) { - e->found = TRUE; + e->found = GL_TRUE; e->data = w; } fgEnumSubWindows( w, fgHavePendingRedisplaysCallback, e ); -} +} static int fgHavePendingRedisplays (void) { SFG_Enumerator enumerator; - enumerator.found = FALSE; + enumerator.found = GL_FALSE; enumerator.data = NULL; fgEnumWindows( fgHavePendingRedisplaysCallback, &enumerator ); return !!enumerator.data; } /* - * Indicates whether there are any outstanding timers. - */ -static int fgHaveTimers( void ) -{ - return !!fgState.Timers.First; -} -/* * 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; } @@ -411,31 +442,44 @@ static long fgNextTimer( void ) */ static void fgSleepForEvents( void ) { -#if TARGET_HOST_UNIX_X11 - fd_set fdset; - int err; - int socket; - struct timeval wait; - long msec; - + long msec; + if( fgState.IdleCallback || fgHavePendingRedisplays( ) ) return; - socket = ConnectionNumber( fgDisplay.Display ); - FD_ZERO( &fdset ); - FD_SET( socket, &fdset ); - + 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 ); - - if( -1 == err ) - printf( "freeglut select() error: %d\n", errno ); - + if( fgHaveJoystick( ) ) /* XXX Use GLUT timers for joysticks... */ + msec = MIN( msec, 10 ); /* XXX Dumb; forces granularity to .01sec */ + +#if TARGET_HOST_UNIX_X11 + /* + * Possibly due to aggressive use of XFlush() and friends, + * it is possible to have our socket drained but still have + * unprocessed events. (Or, this may just be normal with + * X, anyway?) We do non-trivial processing of X events + * after tham in event-reading loop, in any case, so we + * need to allow that we may have an empty socket but non- + * empty event queue. + */ + if( ! XPending( fgDisplay.Display ) ) + { + fd_set fdset; + int err; + int socket; + struct timeval wait; + + socket = ConnectionNumber( fgDisplay.Display ); + FD_ZERO( &fdset ); + FD_SET( socket, &fdset ); + wait.tv_sec = msec / 1000; + wait.tv_usec = (msec % 1000) * 1000; + err = select( socket+1, &fdset, NULL, NULL, &wait ); + + if( -1 == err ) + fgWarning ( "freeglut select() error: %d\n", errno ); + } #elif TARGET_HOST_WIN32 + MsgWaitForMultipleObjects( 0, NULL, FALSE, msec, QS_ALLEVENTS ); #endif } @@ -453,7 +497,7 @@ int fgGetXModifiers( XEvent *event ) ret |= GLUT_ACTIVE_CTRL; if( event->xkey.state & Mod1Mask ) ret |= GLUT_ACTIVE_ALT; - + return ret; } #endif @@ -490,67 +534,100 @@ void FGAPIENTRY glutMainLoopEvent( void ) switch( event.type ) { - case DestroyNotify: + case ClientMessage: /* - * This is sent to confirm the XDestroyWindow call. - * XXX WHY is this commented out? Should we re-enable it? + * Destroy the window when the WM_DELETE_WINDOW message arrives */ - /* fgAddToWindowDestroyList ( window, FALSE ); */ + if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.DeleteWindow ) + { + GETWINDOW( xclient ); + + fgDestroyWindow ( window ); + + if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) + { + fgDeinitialize( ); + exit( 0 ); + } + + fgState.ExecState = GLUT_EXEC_STATE_STOP; + return; + } break; - case ClientMessage: /* - * Destroy the window when the WM_DELETE_WINDOW message arrives + * CreateNotify causes a configure-event so that sub-windows are + * handled compatibly with GLUT. Otherwise, your sub-windows + * (in freeglut only) will not get an initial reshape event, + * which can break things. + * + * 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. */ - if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.DeleteWindow ) + case CreateNotify: + case ConfigureNotify: + GETWINDOW( xconfigure ); { - GETWINDOW( xclient ); + int width = event.xconfigure.width; + int height = event.xconfigure.height; - fgCloseWindow ( window ) ; - fgAddToWindowDestroyList ( window, FALSE ); + 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 MapNotify: - case UnmapNotify: + case DestroyNotify: /* - * If we never do anything with this, can we just not ask to - * get these messages? + * This is sent to confirm the XDestroyWindow call. + * + * XXX WHY is this commented out? Should we re-enable it? */ + /* 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). + * */ if( event.xexpose.count == 0 ) - fghRedrawWindowByHandle( event.xexpose.window ); + { + GETWINDOW( xexpose ); + fgSetWindow( window ); + glutPostRedisplay( ); + } break; + case MapNotify: + case UnmapNotify: /* - * CreateNotify causes a configure-event so that sub-windows are - * handled compatibly with GLUT. Otherwise, your sub-windows - * (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. + * If we never do anything with this, can we just not ask to + * get these messages? */ - case CreateNotify: - case ConfigureNotify: - fghReshapeWindowByHandle( - event.xconfigure.window, - event.xconfigure.width, - event.xconfigure.height - ); break; case MappingNotify: @@ -563,7 +640,10 @@ void FGAPIENTRY glutMainLoopEvent( void ) case VisibilityNotify: { - GETWINDOW( xvisibility ); + GETWINDOW( xvisibility ); + /* + * XXX INVOKE_WCB() does this check for us. + */ if( ! FETCH_WCB( *window, WindowStatus ) ) break; fgSetWindow( window ); @@ -578,18 +658,18 @@ void FGAPIENTRY glutMainLoopEvent( void ) { case VisibilityUnobscured: INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) ); - window->State.Visible = TRUE; + window->State.Visible = GL_TRUE; break; - + case VisibilityPartiallyObscured: INVOKE_WCB( *window, WindowStatus, ( GLUT_PARTIALLY_RETAINED ) ); - window->State.Visible = TRUE; + window->State.Visible = GL_TRUE; break; - + case VisibilityFullyObscured: INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_COVERED ) ); - window->State.Visible = FALSE; + window->State.Visible = GL_FALSE; break; default: @@ -601,34 +681,13 @@ void FGAPIENTRY glutMainLoopEvent( void ) break; case EnterNotify: - { - GETWINDOW( xcrossing ); - GETMOUSE( xcrossing ); - /* - * if( window->Callbacks.Entry ) - * { - * fgSetWindow( window ) ; - * window->Callbacks.Entry( GLUT_ENTERED ); - * } - */ - INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) ); - } - break; - /* XXX Combine EnterNotify and LeaveNotify */ case LeaveNotify: - { GETWINDOW( xcrossing ); GETMOUSE( xcrossing ); - /* - * if( window->Callbacks.Entry ) - * { - * fgSetWindow( window ) ; - * window->Callbacks.Entry( GLUT_LEFT ); - * } - */ - INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) ); - } - break; + INVOKE_WCB( *window, Entry, ( ( EnterNotify == event.type ) ? + GLUT_ENTERED : + GLUT_LEFT ) ); + break; case MotionNotify: { @@ -644,61 +703,37 @@ void FGAPIENTRY glutMainLoopEvent( void ) window->ActiveMenu->Window->State.MouseY = event.xmotion.y_root - window->ActiveMenu->Y; } - window->ActiveMenu->Window->State.Redisplay = TRUE ; - fgSetWindow( window->ActiveMenu->ParentWindow ) ; + window->ActiveMenu->Window->State.Redisplay = GL_TRUE ; + fgSetWindow( window->ActiveMenu->ParentWindow ); break; } /* * 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? */ - if( (event.xmotion.state & Button1Mask) || - (event.xmotion.state & Button2Mask) || - (event.xmotion.state & Button3Mask) || - (event.xmotion.state & Button4Mask) || - (event.xmotion.state & Button5Mask) ) - { - /* - * A mouse button was pressed during the movement... - * Is there a motion callback hooked to the window? - */ - /* - * if( window->Callbacks.Motion ) - * { - * fgSetWindow ( window ) ; - * window->Callbacks.Motion( event.xmotion.x, - * event.xmotion.y ); - * } - */ +#define BUTTON_MASK \ + ( Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) + if ( event.xmotion.state & BUTTON_MASK ) INVOKE_WCB( *window, Motion, ( event.xmotion.x, - event.xmotion.y ) ); - } + event.xmotion.y ) ); else - { - /* - * if( window->Callbacks.Passive ) - * { - * fgSetWindow( window ); - * window->Callbacks.Passive( event.xmotion.x, - * event.xmotion.y ); - * } - */ INVOKE_WCB( *window, Passive, ( event.xmotion.x, - event.xmotion.y ) ); - } + event.xmotion.y ) ); } break; case ButtonRelease: case ButtonPress: { - GLboolean pressed = TRUE; + GLboolean pressed = GL_TRUE; int button; if( event.type == ButtonRelease ) - pressed = FALSE ; + pressed = GL_FALSE ; /* * A mouse button has been pressed or released. Traditionally, @@ -706,7 +741,7 @@ void FGAPIENTRY glutMainLoopEvent( void ) */ GETWINDOW( xbutton ); GETMOUSE( xbutton ); - + /* * An X button (at least in XFree86) is numbered from 1. * A GLUT button is numbered from 0. @@ -717,6 +752,10 @@ void FGAPIENTRY glutMainLoopEvent( void ) button = event.xbutton.button - 1; /* + * XXX This comment is replicated in the WIN32 section and + * XXX maybe also in the menu code. Can we move the info + * XXX to one central place and *reference* it from here? + * * Do not execute the application's mouse callback if a menu * is hooked to this button. In that case an appropriate * private call should be generated. @@ -744,10 +783,10 @@ 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 ) == TRUE ) + window->ActiveMenu ) ) { /* * Save the current window and menu and set the current @@ -771,13 +810,20 @@ 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 ); - - window->State.Redisplay = TRUE; + + /* + * 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; } @@ -785,11 +831,14 @@ void FGAPIENTRY glutMainLoopEvent( void ) * No active menu, let's check whether we need to activate one. */ if( ( 0 <= button ) && - ( 2 >= button ) && + ( FREEGLUT_MAX_MENUS > button ) && ( window->Menu[ button ] ) && pressed ) { - window->State.Redisplay = TRUE; + /* + * XXX Posting a requisite Redisplay seems bogus. + */ + window->State.Redisplay = GL_TRUE; fgSetWindow( window ); fgActivateMenu( window, button ); break; @@ -803,35 +852,19 @@ void FGAPIENTRY glutMainLoopEvent( void ) ! FETCH_WCB( *window, MouseWheel ) ) break; - /* fgSetWindow( window ); */ - - /* - * XXX Why don't we use {window}? Other code here does... - */ - fgStructure.Window->State.Modifiers = fgGetXModifiers( &event ); + 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 < 4 ) || ( ! FETCH_WCB( *window, MouseWheel ) ) ) - { - /* - * if( window->Callbacks.Mouse ) - * fgStructure.Window->Callbacks.Mouse( - * button, - * pressed ? GLUT_DOWN : GLUT_UP, - * event.xbutton.x, - * event.xbutton.y - * ); - */ + if( ( button < 3 ) || ( ! FETCH_WCB( *window, MouseWheel ) ) ) INVOKE_WCB( *window, Mouse, ( button, pressed ? GLUT_DOWN : GLUT_UP, event.xbutton.x, event.xbutton.y ) ); - } else { /* @@ -842,19 +875,15 @@ void FGAPIENTRY glutMainLoopEvent( void ) * XXX since the order and numbering isn't certain * XXX See XFree86 configuration docs (even back in the * XXX 3.x days, and especially with 4.x). + * + * XXX Note that {button} has already been decremeted + * XXX in mapping from X button numbering to GLUT. */ - int wheel_number = (button - 4) / 2; - int direction = (button & 1)*2 - 1; - - /* - * if( pressed ) - * fgStructure.Window->Callbacks.MouseWheel( - * wheel_number, - * direction, - * event.xbutton.x, - * event.xbutton.y - * ); - */ + int wheel_number = (button - 3) / 2; + int direction = -1; + if( button % 2 ) + direction = 1; + if( pressed ) INVOKE_WCB( *window, MouseWheel, ( wheel_number, direction, @@ -866,7 +895,7 @@ void FGAPIENTRY glutMainLoopEvent( void ) /* * Trash the modifiers state */ - fgStructure.Window->State.Modifiers = 0xffffffff; + fgState.Modifiers = 0xffffffff; } break; @@ -904,7 +933,8 @@ void FGAPIENTRY glutMainLoopEvent( void ) * Check for the ASCII/KeySym codes associated with the event: */ len = XLookupString( &event.xkey, asciiCode, sizeof(asciiCode), - &keySym, &composeStatus ); + &keySym, &composeStatus + ); /* * GLUT API tells us to have two separate callbacks... @@ -917,10 +947,11 @@ void FGAPIENTRY glutMainLoopEvent( void ) if( keyboard_cb ) { fgSetWindow( window ); - window->State.Modifiers = fgGetXModifiers( &event ); + fgState.Modifiers = fgGetXModifiers( &event ); keyboard_cb( asciiCode[ 0 ], - event.xkey.x, event.xkey.y ); - window->State.Modifiers = 0xffffffff; + event.xkey.x, event.xkey.y + ); + fgState.Modifiers = 0xffffffff; } } else @@ -970,15 +1001,18 @@ void FGAPIENTRY glutMainLoopEvent( void ) if( special_cb && (special != -1) ) { fgSetWindow( window ); - window->State.Modifiers = fgGetXModifiers( &event ); + fgState.Modifiers = fgGetXModifiers( &event ); special_cb( special, event.xkey.x, event.xkey.y ); - window->State.Modifiers = 0xffffffff; + fgState.Modifiers = 0xffffffff; } } } } break; + case ReparentNotify: + break; /* XXX Should disable this event */ + default: fgWarning ("Unknown X event type: %d", event.type); break; @@ -992,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( ); @@ -1012,6 +1055,8 @@ void FGAPIENTRY glutMainLoopEvent( void ) */ void FGAPIENTRY glutMainLoop( void ) { + int action; + #if TARGET_HOST_WIN32 SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ; #endif @@ -1034,14 +1079,10 @@ void FGAPIENTRY glutMainLoop( void ) { SFG_Window *current_window = fgStructure.Window ; - /* - * fgSetWindow( window ); - * window->Callbacks.Visibility ( window->State.Visible ) ; - */ INVOKE_WCB( *window, Visibility, ( window->State.Visible ) ); fgSetWindow( current_window ); } - + window = (SFG_Window *)window->Node.Next ; } #endif @@ -1049,31 +1090,40 @@ void FGAPIENTRY glutMainLoop( void ) fgState.ExecState = GLUT_EXEC_STATE_RUNNING ; while( fgState.ExecState == GLUT_EXEC_STATE_RUNNING ) { + SFG_Window *window; + 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( fgStructure.Windows.First == NULL ) + 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 + * + * Save the "ActionOnWindowClose" because "fgDeinitialize" resets it. + */ + action = fgState.ActionOnWindowClose; + fgDeinitialize( ); + if( action == GLUT_ACTION_EXIT ) + exit( 0 ); } /* @@ -1111,7 +1161,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LONG lRet = 1; if ( ( window == NULL ) && ( uMsg != WM_CREATE ) ) - return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ); + return DefWindowProc( hWnd, uMsg, wParam, lParam ); /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0, uMsg, wParam, lParam ); */ @@ -1126,16 +1176,17 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, window->Window.Handle = hWnd; window->Window.Device = GetDC( hWnd ); - if( fgState.BuildingAMenu ) + if( window->IsMenu ) { unsigned int current_DisplayMode = fgState.DisplayMode; fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH; - fgSetupPixelFormat( window, FALSE, PFD_MAIN_PLANE ); + fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); fgState.DisplayMode = current_DisplayMode; if( fgStructure.MenuContext ) wglMakeCurrent( window->Window.Device, - fgStructure.MenuContext->Context ) ; + fgStructure.MenuContext->Context + ); else { fgStructure.MenuContext = @@ -1144,14 +1195,14 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, wglCreateContext( window->Window.Device ); } - /* window->Window.Context = wglGetCurrentContext () ; */ + /* window->Window.Context = wglGetCurrentContext (); */ window->Window.Context = wglCreateContext( window->Window.Device ); } else { - fgSetupPixelFormat( window, FALSE, PFD_MAIN_PLANE ); + fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); - if( fgState.UseCurrentContext != TRUE ) + if( ! fgState.UseCurrentContext ) window->Window.Context = wglCreateContext( window->Window.Device ); else @@ -1163,23 +1214,34 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, } } - window->State.NeedToResize = TRUE; + window->State.NeedToResize = GL_TRUE; + window->State.Width = fgState.Size.X; + window->State.Height = fgState.Size.Y; + ReleaseDC( window->Window.Handle, window->Window.Device ); break; case WM_SIZE: /* - * We got resized... But check if the window has been already added... + * If the window is visible, then it is the user manually resizing it. + * If it is not, then it is the system sending us a dummy resize with + * zero dimensions on a "glutIconifyWindow" call. */ - fghReshapeWindowByHandle( hWnd, LOWORD(lParam), HIWORD(lParam) ); + if( window->State.Visible ) + { + window->State.NeedToResize = GL_TRUE; + window->State.Width = LOWORD(lParam); + window->State.Height = HIWORD(lParam); + } + break; #if 0 - case WM_SETFOCUS: + case WM_SETFOCUS: printf("WM_SETFOCUS: %p\n", window ); lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); break; - case WM_ACTIVATE: + case WM_ACTIVATE: if (LOWORD(wParam) != WA_INACTIVE) { /* glutSetCursor( fgStructure.Window->State.Cursor ); */ @@ -1192,16 +1254,15 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, break; #endif - case WM_SETCURSOR: /* - * Windows seems to need reminding to erase the cursor for NONE. + * XXX Why not re-use some common code with the glutSetCursor() + * XXX function (or perhaps invoke glutSetCursor())? + * XXX That is, why are we duplicating code, here, from + * XXX glutSetCursor()? The WIN32 code should be able to just + * XXX call glutSetCurdsor() instead of defining two macros + * XXX and implementing a nested case in-line. */ -#if 0 - if ((LOWORD(lParam) == HTCLIENT) && - (fgStructure.Window->State.Cursor == GLUT_CURSOR_NONE)) - SetCursor( NULL ); -#else - + case WM_SETCURSOR: /* Set the cursor AND change it for this window class. */ #define MAP_CURSOR(a,b) \ case a: \ @@ -1233,55 +1294,27 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, default: MAP_CURSOR( GLUT_CURSOR_UP_DOWN, IDC_ARROW ); } -#endif else lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); break; case WM_SHOWWINDOW: - window->State.Visible = TRUE; - window->State.Redisplay = TRUE; + window->State.Visible = GL_TRUE; + window->State.Redisplay = GL_TRUE; break; case WM_PAINT: + /* Turn on the visibility in case it was turned off somehow */ + window->State.Visible = GL_TRUE; BeginPaint( hWnd, &ps ); fghRedrawWindowByHandle( hWnd ); EndPaint( hWnd, &ps ); 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 == FALSE ) - wglDeleteContext( window->Window.Context ); - } - - /* - * Put on a linked list of windows to be removed after all the - * callbacks have returned - */ - fgAddToWindowDestroyList( window, FALSE ); - DestroyWindow( hWnd ); + fgDestroyWindow ( window ); + if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION ) + PostQuitMessage(0); break; case WM_DESTROY: @@ -1294,46 +1327,26 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, { window->State.MouseX = LOWORD( lParam ); window->State.MouseY = HIWORD( lParam ); - + if ( window->ActiveMenu ) { - window->State.Redisplay = TRUE; + window->State.Redisplay = GL_TRUE; fgSetWindow ( window->ActiveMenu->ParentWindow ); break; } - window->State.Modifiers = fgGetWin32Modifiers( ); + fgState.Modifiers = fgGetWin32Modifiers( ); if( ( wParam & MK_LBUTTON ) || ( wParam & MK_MBUTTON ) || ( wParam & MK_RBUTTON ) ) - { - /* - * if( window->Callbacks.Motion ) - * { - * fgSetWindow( window ); - * window->Callbacks.Motion( window->State.MouseX, - * window->State.MouseY ); - * } - */ INVOKE_WCB( *window, Motion, ( window->State.MouseX, window->State.MouseY ) ); - } else - { - /* - * if( window->Callbacks.Passive ) - * { - * fgSetWindow( window ); - * window->Callbacks.Passive( window->State.MouseX, - * window->State.MouseY ); - * } - */ INVOKE_WCB( *window, Passive, ( window->State.MouseX, window->State.MouseY ) ); - } - window->State.Modifiers = 0xffffffff; + fgState.Modifiers = 0xffffffff; } break; @@ -1344,7 +1357,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, case WM_MBUTTONUP: case WM_RBUTTONUP: { - GLboolean pressed = TRUE; + GLboolean pressed = GL_TRUE; int button; window->State.MouseX = LOWORD( lParam ); @@ -1353,31 +1366,51 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, switch( uMsg ) { case WM_LBUTTONDOWN: - pressed = TRUE; button = GLUT_LEFT_BUTTON; break; + pressed = GL_TRUE; + button = GLUT_LEFT_BUTTON; + break; case WM_MBUTTONDOWN: - pressed = TRUE; button = GLUT_MIDDLE_BUTTON; break; + pressed = GL_TRUE; + button = GLUT_MIDDLE_BUTTON; + break; case WM_RBUTTONDOWN: - pressed = TRUE; button = GLUT_RIGHT_BUTTON; break; + pressed = GL_TRUE; + button = GLUT_RIGHT_BUTTON; + break; case WM_LBUTTONUP: - pressed = FALSE; button = GLUT_LEFT_BUTTON; break; + pressed = GL_FALSE; + button = GLUT_LEFT_BUTTON; + break; case WM_MBUTTONUP: - pressed = FALSE; button = GLUT_MIDDLE_BUTTON; break; + pressed = GL_FALSE; + button = GLUT_MIDDLE_BUTTON; + break; case WM_RBUTTONUP: - pressed = FALSE; button = GLUT_RIGHT_BUTTON; break; + pressed = GL_FALSE; + button = GLUT_RIGHT_BUTTON; + break; default: - pressed = FALSE; button = -1; break; + pressed = GL_FALSE; + button = -1; + break; } if( GetSystemMetrics( SM_SWAPBUTTON ) ) + { if( button == GLUT_LEFT_BUTTON ) button = GLUT_RIGHT_BUTTON; - else if( button == GLUT_RIGHT_BUTTON ) - button = GLUT_LEFT_BUTTON; + else + if( button == GLUT_RIGHT_BUTTON ) + button = GLUT_LEFT_BUTTON; + } if( button == -1 ) return DefWindowProc( hWnd, uMsg, lParam, wParam ); /* + * XXX This comment is duplicated in two other spots. + * XXX Can we centralize it? + * * Do not execute the application's mouse callback if a * menu is hooked to this button. * In that case an appropriate private call should be generated. @@ -1397,8 +1430,13 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, /* Window has an active menu, it absorbs any mouse click */ if( window->ActiveMenu ) { - /* Inside the menu, invoke the callback and deactivate the menu*/ - if( fgCheckActiveMenu( window, window->ActiveMenu ) == TRUE ) + /* Outside the menu, deactivate the menu if it's a downclick */ + if( ! fgCheckActiveMenu( window, window->ActiveMenu ) ) + { + if( pressed ) + fgDeactivateMenu( window->ActiveMenu->ParentWindow ); + } + else /* In menu, invoke the callback and deactivate the menu*/ { /* * Save the current window and menu and set the current @@ -1418,25 +1456,20 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, fgSetWindow( save_window ); fgStructure.Menu = save_menu; } - else /* Out of menu, deactivate the menu if it's a downclick */ - { - if( pressed == TRUE ) - fgDeactivateMenu( window->ActiveMenu->ParentWindow ); - } /* * Let's make the window redraw as a result of the mouse * click and menu activity. */ if( ! window->IsMenu ) - window->State.Redisplay = TRUE; + window->State.Redisplay = GL_TRUE; break; } - if ( ( window->Menu[ button ] ) && ( pressed == TRUE ) ) + if( window->Menu[ button ] && pressed ) { - window->State.Redisplay = TRUE; + window->State.Redisplay = GL_TRUE; fgSetWindow( window ); fgActivateMenu( window, button ); @@ -1447,36 +1480,30 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, break; fgSetWindow( window ); - fgStructure.Window->State.Modifiers = fgGetWin32Modifiers( ); + fgState.Modifiers = fgGetWin32Modifiers( ); INVOKE_WCB( *window, Mouse, ( button, - pressed == TRUE ? GLUT_DOWN : GLUT_UP, + pressed ? GLUT_DOWN : GLUT_UP, window->State.MouseX, window->State.MouseY ) ); - /* - * window->Callbacks.Mouse( - * button, - * pressed == TRUE ? GLUT_DOWN : GLUT_UP, - * window->State.MouseX, - * window->State.MouseY - * ); - */ - fgStructure.Window->State.Modifiers = 0xffffffff; + fgState.Modifiers = 0xffffffff; } break; case 0x020a: /* Should be WM_MOUSEWHEEL but my compiler doesn't recognize it */ { + /* + * XXX THIS IS SPECULATIVE -- John Fay, 10/2/03 + * XXX Should use WHEEL_DELTA instead of 120 + */ int wheel_number = LOWORD( wParam ); - /* THIS IS SPECULATIVE -- John Fay, 10/2/03 */ - short ticks = HIWORD( lParam ) / 120; - /* Should be WHEEL_DELTA instead of 120 */ + short ticks = ( short )HIWORD( wParam ) / 120; int direction = 1; if( ticks < 0 ) @@ -1498,11 +1525,10 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, break; fgSetWindow( window ); - fgStructure.Window->State.Modifiers = fgGetWin32Modifiers( ); + fgState.Modifiers = fgGetWin32Modifiers( ); while( ticks-- ) if( FETCH_WCB( *window, MouseWheel ) ) - { INVOKE_WCB( *window, MouseWheel, ( wheel_number, direction, @@ -1510,16 +1536,6 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, window->State.MouseY ) ); - } - /* - * if( window->Callbacks.MouseWheel ) - * window->Callbacks.MouseWheel( - * wheel_number, - * direction, - * window->State.MouseX, - * window->State.MouseY - * ); - */ else /* No mouse wheel, call the mouse button callback twice */ { /* @@ -1537,20 +1553,9 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, ( button, GLUT_UP, window->State.MouseX, window->State.MouseX ) ); - - /* - * window->Callbacks.Mouse( button, GLUT_DOWN, - * window->State.MouseX, - * window->State.MouseY - * ); - * window->Callbacks.Mouse( button, GLUT_UP, - * window->State.MouseX, - * window->State.MouseY - * ); - */ } - fgStructure.Window->State.Modifiers = 0xffffffff; + fgState.Modifiers = 0xffffffff; } break ; @@ -1560,14 +1565,14 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, int keypress = -1; POINT mouse_pos ; - if( fgState.IgnoreKeyRepeat && (lParam & KF_REPEAT) ) + if( fgState.IgnoreKeyRepeat && (HIWORD(lParam) & KF_REPEAT) ) break; /* - * Remember the current modifiers state. This is done here in order + * Remember the current modifiers state. This is done here in order * to make sure the VK_DELETE keyboard callback is executed properly. */ - window->State.Modifiers = fgGetWin32Modifiers( ); + fgState.Modifiers = fgGetWin32Modifiers( ); GetCursorPos( &mouse_pos ); ScreenToClient( window->Window.Handle, &mouse_pos ); @@ -1608,32 +1613,18 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, /* * The delete key should be treated as an ASCII keypress: */ - /* - * if( window->Callbacks.Keyboard ) - * { - * fgSetWindow( window ); - * window->Callbacks.Keyboard( 127, window->State.MouseX, - * window->State.MouseY ); - * } - */ INVOKE_WCB( *window, Keyboard, ( 127, window->State.MouseX, window->State.MouseY ) ); } - /* if( ( keypress != -1 ) && window->Callbacks.Special ) - * { - * fgSetWindow( window ); - * window->Callbacks.Special( keypress, window->State.MouseX, - * window->State.MouseY ); - * } - */ if( keypress != -1 ) INVOKE_WCB( *window, Special, - ( keypress, window->State.MouseX, window->State.MouseY ) + ( keypress, + window->State.MouseX, window->State.MouseY ) ); - window->State.Modifiers = 0xffffffff; + fgState.Modifiers = 0xffffffff; } break; @@ -1644,10 +1635,10 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, POINT mouse_pos; /* - * Remember the current modifiers state. This is done here in order + * Remember the current modifiers state. This is done here in order * to make sure the VK_DELETE keyboard callback is executed properly. */ - window->State.Modifiers = fgGetWin32Modifiers( ); + fgState.Modifiers = fgGetWin32Modifiers( ); GetCursorPos( &mouse_pos ); ScreenToClient( window->Window.Handle, &mouse_pos ); @@ -1688,13 +1679,6 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, /* * The delete key should be treated as an ASCII keypress: */ - /* if( window->Callbacks.KeyboardUp ) - * { - * fgSetWindow( window ); - * window->Callbacks.KeyboardUp( 127, window->State.MouseX, - * window->State.MouseY ); - * } - */ INVOKE_WCB( *window, KeyboardUp, ( 127, window->State.MouseX, window->State.MouseY ) ); @@ -1704,21 +1688,12 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, { BYTE state[ 256 ]; WORD code[ 2 ]; - + GetKeyboardState( state ); - + if( ToAscii( wParam, 0, state, code, 0 ) == 1 ) wParam=code[ 0 ]; - /* - * if( window->Callbacks.KeyboardUp ) - * { - * fgSetWindow( window ); - * window->Callbacks.KeyboardUp( (char)wParam, - * window->State.MouseX, - * window->State.MouseY ); - * } - */ INVOKE_WCB( *window, KeyboardUp, ( (char)wParam, window->State.MouseX, window->State.MouseY ) @@ -1726,57 +1701,36 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, } } - /* - * if( (keypress != -1) && window->Callbacks.SpecialUp ) - * { - * fgSetWindow( window ); - * window->Callbacks.SpecialUp( keypress, window->State.MouseX, - * window->State.MouseY ); - * } - */ if( keypress != -1 ) INVOKE_WCB( *window, SpecialUp, ( keypress, window->State.MouseX, window->State.MouseY ) ); - window->State.Modifiers = 0xffffffff; + fgState.Modifiers = 0xffffffff; } break; case WM_SYSCHAR: case WM_CHAR: { - if( fgState.IgnoreKeyRepeat && (lParam & KF_REPEAT) ) + if( fgState.IgnoreKeyRepeat && (HIWORD(lParam) & KF_REPEAT) ) break; - if( FETCH_WCB( *window, Keyboard ) ) - { - /* fgSetWindow( window ); */ - window->State.Modifiers = fgGetWin32Modifiers( ); - /* window->Callbacks.Keyboard( (char)wParam, window->State.MouseX, - window->State.MouseY ); */ - INVOKE_WCB( *window, Keyboard, - ( (char)wParam, - window->State.MouseX, window->State.MouseY ) - ); - window->State.Modifiers = 0xffffffff; - } + fgState.Modifiers = fgGetWin32Modifiers( ); + INVOKE_WCB( *window, Keyboard, + ( (char)wParam, + window->State.MouseX, window->State.MouseY ) + ); + fgState.Modifiers = 0xffffffff; } break; case WM_CAPTURECHANGED: /* User has finished resizing the window, force a redraw */ - /* - * if( window->Callbacks.Display ) - * { - * fgSetWindow( window ); - * window->Callbacks.Display( ); - * } - */ INVOKE_WCB( *window, Display, ( ) ); - /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ) ; */ + /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */ break; /* @@ -1807,7 +1761,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, case WM_SYNCPAINT: /* 0x0088 */ /* Another window has moved, need to update this one */ - window->State.Redisplay = TRUE; + window->State.Redisplay = GL_TRUE; lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); /* Help screen says this message must be passed to "DefWindowProc" */ break; @@ -1818,6 +1772,75 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, /* Pass it on to "DefWindowProc" to repaint a standard border */ break; + case WM_SYSCOMMAND : /* 0x0112 */ + { + /* + * We have received a system command message. Try to act on it. + * The commands are passed in through the "lParam" parameter: + * Clicking on a corner to resize the window gives a "F004" message + * but this is not defined in my header file. + */ + switch ( lParam ) + { + case SC_SIZE : + break ; + + case SC_MOVE : + break ; + + case SC_MINIMIZE : + /* User has clicked on the "-" to minimize the window */ + /* Turn off the visibility */ + window->State.Visible = GL_FALSE ; + + break ; + + case SC_MAXIMIZE : + break ; + + case SC_NEXTWINDOW : + break ; + + case SC_PREVWINDOW : + break ; + + case SC_CLOSE : + /* Followed very closely by a WM_CLOSE message */ + break ; + + case SC_VSCROLL : + break ; + + case SC_HSCROLL : + break ; + + case SC_MOUSEMENU : + break ; + + case SC_KEYMENU : + break ; + + case SC_ARRANGE : + break ; + + case SC_RESTORE : + break ; + + case SC_TASKLIST : + break ; + + case SC_SCREENSAVE : + break ; + + case SC_HOTKEY : + break ; + } + } + + /* We need to pass the message on to the operating system as well */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + default: /* * Handle unhandled messages