X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ffreeglut_main.c;h=17634610f0af3896ab688076ba53dff80fc4901e;hb=4f58e4f75c3d57437da215f4119e9991b77272e0;hp=b42f9a05a362bd42d6d6f88262395717f9965570;hpb=093a727b18a11d85c8e51b5398b86a7d3bed94c9;p=freeglut diff --git a/src/freeglut_main.c b/src/freeglut_main.c index b42f9a0..1763461 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 @@ -180,14 +180,14 @@ static void fghRedrawWindowByHandle ( SFG_WindowHandleType handle ) fgSetWindow( window ); - fghReshapeWindowByHandle( + fghReshapeWindowByHandle( window->Window.Handle, window->State.Width, window->State.Height ); window->State.NeedToResize = GL_FALSE; - fgSetWindow ( current_window ); + fgSetWindow( current_window ); } INVOKE_WCB( *window, Display, ( ) ); @@ -199,40 +199,25 @@ static void fghRedrawWindowByHandle ( SFG_WindowHandleType handle ) static void fghcbDisplayWindow( SFG_Window *window, SFG_Enumerator *enumerator ) { - if( window->State.Redisplay && - window->State.Visible ) + if( window->State.NeedToResize ) { - /* - * 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; + SFG_Window *current_window = fgStructure.Window; - fgSetWindow( window ); + fgSetWindow( window ); - fghReshapeWindowByHandle( - window->Window.Handle, - window->State.Width, - window->State.Height - ); + fghReshapeWindowByHandle( + window->Window.Handle, + window->State.Width, + window->State.Height + ); - window->State.NeedToResize = GL_FALSE; - fgSetWindow ( current_window ); - } + window->State.NeedToResize = GL_FALSE; + fgSetWindow ( current_window ); + } + if( window->State.Redisplay && + window->State.Visible ) + { window->State.Redisplay = GL_FALSE; #if TARGET_HOST_UNIX_X11 @@ -244,7 +229,7 @@ static void fghcbDisplayWindow( SFG_Window *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 @@ -303,10 +288,11 @@ static void fghCheckJoystickPolls( void ) static void fghCheckTimers( void ) { long checkTime = fgElapsedTime( ); - SFG_Timer *timer; - while( timer = fgState.Timers.First ) + while( fgState.Timers.First ) { + SFG_Timer *timer = fgState.Timers.First; + if( timer->TriggerTime > checkTime ) break; @@ -393,20 +379,12 @@ 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. - * - * Some alternatives: - * * Store Joystick data into freeglut global state. - * * Provide NON-static functions or data from Joystick *.c file. + * there is a joystick callback. We have a short-circuit early + * return if we find any joystick handler registered. * - * 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) @@ -434,7 +412,7 @@ static void fgHavePendingRedisplaysCallback( SFG_Window* w, SFG_Enumerator* e) e->data = w; } fgEnumSubWindows( w, fgHavePendingRedisplaysCallback, e ); -} +} static int fgHavePendingRedisplays (void) { SFG_Enumerator enumerator; @@ -464,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 ); + msec = fgNextTimer( ); + if( fgHaveJoystick( ) ) /* XXX Use GLUT timers for joysticks... */ + msec = MIN( msec, 10 ); /* XXX Dumb; forces granularity to .01sec */ - if( -1 == err ) - fgWarning ( "freeglut select() error: %d\n", errno ); - +#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 } @@ -506,7 +497,7 @@ int fgGetXModifiers( XEvent *event ) ret |= GLUT_ACTIVE_CTRL; if( event->xkey.state & Mod1Mask ) ret |= GLUT_ACTIVE_ALT; - + return ret; } #endif @@ -549,7 +540,7 @@ void FGAPIENTRY glutMainLoopEvent( void ) */ if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.DeleteWindow ) { - GETWINDOW( xclient ); + GETWINDOW( xclient ); fgDestroyWindow ( window ); @@ -607,6 +598,7 @@ void FGAPIENTRY glutMainLoopEvent( void ) case DestroyNotify: /* * This is sent to confirm the XDestroyWindow call. + * * XXX WHY is this commented out? Should we re-enable it? */ /* fgAddToWindowDestroyList ( window ); */ @@ -621,12 +613,13 @@ void FGAPIENTRY glutMainLoopEvent( void ) * 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 ); + { + GETWINDOW( xexpose ); + fgSetWindow( window ); + glutPostRedisplay( ); + } break; case MapNotify: @@ -647,7 +640,7 @@ void FGAPIENTRY glutMainLoopEvent( void ) case VisibilityNotify: { - GETWINDOW( xvisibility ); + GETWINDOW( xvisibility ); /* * XXX INVOKE_WCB() does this check for us. */ @@ -667,13 +660,13 @@ void FGAPIENTRY glutMainLoopEvent( void ) INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) ); window->State.Visible = GL_TRUE; break; - + case VisibilityPartiallyObscured: INVOKE_WCB( *window, WindowStatus, ( GLUT_PARTIALLY_RETAINED ) ); window->State.Visible = GL_TRUE; break; - + case VisibilityFullyObscured: INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_COVERED ) ); window->State.Visible = GL_FALSE; @@ -748,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. @@ -790,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 ) ) @@ -890,7 +883,7 @@ void FGAPIENTRY glutMainLoopEvent( void ) int direction = -1; if( button % 2 ) direction = 1; - + if( pressed ) INVOKE_WCB( *window, MouseWheel, ( wheel_number, direction, @@ -915,6 +908,34 @@ void FGAPIENTRY glutMainLoopEvent( void ) GETWINDOW( xkey ); GETMOUSE( xkey ); + /* Detect auto repeated keys, if configured globally or per-window */ + + if ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) + { + if (event.type==KeyRelease) + { + /* + * Look at X11 keystate to detect repeat mode. + * While X11 says the key is actually held down, we'll ignore KeyRelease/KeyPress pairs. + */ + + char keys[32]; + XQueryKeymap( fgDisplay.Display, keys ); /* Look at X11 keystate to detect repeat mode */ + + if ( keys[event.xkey.keycode>>3] & (1<<(event.xkey.keycode%8)) ) + window->State.KeyRepeating = GL_TRUE; + else + window->State.KeyRepeating = GL_FALSE; + } + } + else + window->State.KeyRepeating = GL_FALSE; + + /* Cease processing this event if it is auto repeated */ + + if (window->State.KeyRepeating) + break; + if( event.type == KeyPress ) { keyboard_cb = FETCH_WCB( *window, Keyboard ); @@ -1062,6 +1083,8 @@ void FGAPIENTRY glutMainLoopEvent( void ) */ void FGAPIENTRY glutMainLoop( void ) { + int action; + #if TARGET_HOST_WIN32 SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ; #endif @@ -1087,7 +1110,7 @@ void FGAPIENTRY glutMainLoop( void ) INVOKE_WCB( *window, Visibility, ( window->State.Visible ) ); fgSetWindow( current_window ); } - + window = (SFG_Window *)window->Node.Next ; } #endif @@ -1101,13 +1124,13 @@ void FGAPIENTRY glutMainLoop( void ) /* * 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 @@ -1122,9 +1145,12 @@ void FGAPIENTRY glutMainLoop( void ) /* * 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( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) + if( action == GLUT_ACTION_EXIT ) exit( 0 ); } @@ -1225,19 +1251,25 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, 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. */ - window->State.NeedToResize = GL_TRUE; - window->State.Width = LOWORD(lParam); - window->State.Height = 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 ); */ @@ -1258,7 +1290,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, * XXX call glutSetCurdsor() instead of defining two macros * XXX and implementing a nested case in-line. */ - case WM_SETCURSOR: + case WM_SETCURSOR: /* Set the cursor AND change it for this window class. */ #define MAP_CURSOR(a,b) \ case a: \ @@ -1323,7 +1355,7 @@ 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 = GL_TRUE; @@ -1392,10 +1424,13 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, } 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 ); @@ -1558,11 +1593,11 @@ 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. */ fgState.Modifiers = fgGetWin32Modifiers( ); @@ -1628,7 +1663,7 @@ 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. */ fgState.Modifiers = fgGetWin32Modifiers( ); @@ -1681,9 +1716,9 @@ 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 ]; @@ -1707,7 +1742,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, case WM_SYSCHAR: case WM_CHAR: { - if( fgState.IgnoreKeyRepeat && (lParam & KF_REPEAT) ) + if( fgState.IgnoreKeyRepeat && (HIWORD(lParam) & KF_REPEAT) ) break; fgState.Modifiers = fgGetWin32Modifiers( );