Resolved bug #869765 glutIgnoreKeyRepeat() Fix (Win32)
[freeglut] / src / freeglut_main.c
index 4a4d9c6..9bc7a91 100644 (file)
@@ -29,7 +29,7 @@
 #include "config.h"
 #endif
 
-#include "../include/GL/freeglut.h"
+#include <GL/freeglut.h>
 #include "freeglut_internal.h"
 
 #include <limits.h>
@@ -87,42 +87,49 @@ 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
         );
     }
 
@@ -180,7 +187,7 @@ static void fghRedrawWindowByHandle ( SFG_WindowHandleType handle )
         );
 
         window->State.NeedToResize = GL_FALSE;
-        fgSetWindow ( current_window );
+        fgSetWindow( current_window );
     }
 
     INVOKE_WCB( *window, Display, ( ) );
@@ -192,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
@@ -296,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;
 
@@ -386,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)
@@ -457,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
 }
 
@@ -600,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 ); */
@@ -614,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:
@@ -1055,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
@@ -1115,9 +1117,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 );
 }
 
@@ -1218,11 +1223,17 @@ 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: 
@@ -1385,10 +1396,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 );
@@ -1551,7 +1565,7 @@ 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;
 
         /*
@@ -1700,7 +1714,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( );