MenuStatusCallback when menu was closed did not return location of pointer relative...
[freeglut] / src / mswin / fg_main_mswin.c
index 6de07a2..4ee9008 100644 (file)
@@ -128,33 +128,51 @@ void fgPlatformProcessSingleEvent ( void )
 
 
 
-void fgPlatformMainLoopPreliminaryWork ( void )
+static void fghUpdateWindowStatus(SFG_Window *window, GLboolean visState)
 {
-    SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ;
-
-    /*
-     * Processing before the main loop:  If there is a window which is open and
-     * which has a visibility callback, call it.  I know this is an ugly hack,
-     * but I'm not sure what else to do about it.  Ideally we should leave
-     * something uninitialized in the create window code and initialize it in
-     * the main loop, and have that initialization create a "WM_ACTIVATE"
-     * message.  Then we would put the visibility callback code in the
-     * "case WM_ACTIVATE" block below.         - John Fay -- 10/24/02
-     */
-    while( window )
+    SFG_Window* child;
+
+    if (window->State.Visible != visState)
     {
-        if ( FETCH_WCB( *window, Visibility ) )
-        {
-            SFG_Window *current_window = fgStructure.CurrentWindow ;
+        window->State.Visible = visState;
+        /* On win32 we only have two states, window displayed and window not displayed (iconified) 
+         * We map these to GLUT_FULLY_RETAINED and GLUT_HIDDEN respectively.
+         */
+        INVOKE_WCB( *window, WindowStatus, ( visState ? GLUT_FULLY_RETAINED:GLUT_HIDDEN ) );
 
-            INVOKE_WCB( *window, Visibility, ( window->State.Visible ) );
-            fgSetWindow( current_window );
+        /* If top level window (not a subwindow/child), and icon title text available, switch titles based on visibility state */
+        if (!window->Parent && window->State.pWState.IconTitle)
+        {
+            if (visState)
+                /* visible, set window title */
+                SetWindowText( window->Window.Handle, window->State.pWState.WindowTitle );
+            else
+                /* not visible, set icon title */
+                SetWindowText( window->Window.Handle, window->State.pWState.IconTitle );
         }
+    }
 
-        window = (SFG_Window *)window->Node.Next ;
+    /* Also set visibility state for children */
+    for( child = ( SFG_Window * )window->Children.First;
+         child;
+         child = ( SFG_Window * )child->Node.Next )
+    {
+        fghUpdateWindowStatus(child, visState);
     }
 }
 
+void fghNotifyWindowStatus(SFG_Window *window)
+{
+    INVOKE_WCB( *window, WindowStatus, ( window->State.Visible?GLUT_FULLY_RETAINED:GLUT_HIDDEN ) );
+
+    /* Don't notify children, they get their own just before first time they're drawn */
+}
+
+void fgPlatformMainLoopPreliminaryWork ( void )
+{
+    /* no-op */
+}
+
 
 /*
  * Determine a GLUT modifier mask based on MS-WINDOWS system info.
@@ -170,27 +188,25 @@ static int fgPlatformGetModifiers (void)
             ( GetKeyState( VK_RMENU    ) < 0 )) ? GLUT_ACTIVE_ALT   : 0 );
 }
 
-static LRESULT fghKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPARAM wParam, LPARAM lParam)
+static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPARAM wParam, LPARAM lParam)
 {
     static unsigned char lControl = 0, lShift = 0, lAlt = 0,
                          rControl = 0, rShift = 0, rAlt = 0;
 
     int keypress = -1;
-    POINT mouse_pos ;
     
     /* if keydown, check for repeat */
+    /* If repeat is globally switched off, it cannot be switched back on per window.
+     * But if it is globally switched on, it can be switched off per window. This matches
+     * GLUT's behavior on X11, but not Nate Robbins' win32 GLUT, as he didn't implement the
+     * global state switch.
+     */
     if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
         return 1;
     
     /* Remember the current modifiers state so user can query it from their callback */
     fgState.Modifiers = fgPlatformGetModifiers( );
 
-    /* Get mouse position roughly at time of keypress */
-    GetCursorPos( &mouse_pos );
-    ScreenToClient( window->Window.Handle, &mouse_pos );
-    window->State.MouseX = mouse_pos.x;
-    window->State.MouseY = mouse_pos.y;
-
     /* Convert the Win32 keystroke codes to GLUTtish way */
 #   define KEY(a,b) case a: keypress = b; break;
 
@@ -323,14 +339,47 @@ static LRESULT fghKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPA
         return 1;
 }
 
+static SFG_Window* fghWindowUnderCursor(SFG_Window *window)
+{
+    /* Check if the current window that the mouse is over is a child window
+     * of the window the message was sent to. Some events only sent to main window,
+     * and when handling some messages, we need to make sure that we process
+     * callbacks on the child window instead. This mirrors how GLUT does things.
+     * returns either the original window or the found child.
+     */
+    if (window && window->Children.First)   /* This window has childs */
+    {
+        HWND hwnd;
+        SFG_Window* child_window;
+
+        /* Get mouse position at time of message */
+        DWORD mouse_pos_dw = GetMessagePos();
+        POINT mouse_pos = {GET_X_LPARAM(mouse_pos_dw), GET_Y_LPARAM(mouse_pos_dw)};
+        ScreenToClient( window->Window.Handle, &mouse_pos );
+        
+        hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
+        if (hwnd && hwnd!=window->Window.Handle)   /* can be NULL if mouse outside parent by the time we get here, or can be same as parent if we didn't find a child */
+        {
+            child_window = fgWindowByHandle(hwnd);
+            if (child_window)    /* Verify we got a FreeGLUT window */
+            {
+                /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */
+                window = fghWindowUnderCursor(child_window);
+            }
+        }
+    }
+
+    return window;
+}
+
 /*
  * The window procedure for handling Win32 events
  */
 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
 {
-    SFG_Window *window, *child_window = NULL;
-    PAINTSTRUCT ps;
+    SFG_Window *window;
     LRESULT lRet = 1;
+    static int setCaptureActive = 0;
 
     FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
 
@@ -342,28 +391,6 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
     /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
              uMsg, wParam, lParam ); */
 
-    /* Some events only sent to main window. Check if the current window that
-     * the mouse is over is a child window. Below when handling some messages,
-     * we make sure that we process callbacks on the child window instead.
-     * This mirrors how GLUT does things.
-     */
-    if (window && window->Children.First)
-    {
-        POINT mouse_pos;
-        SFG_WindowHandleType hwnd;
-        SFG_Window* temp_window;
-
-        GetCursorPos( &mouse_pos );
-        ScreenToClient( window->Window.Handle, &mouse_pos );
-        hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
-        if (hwnd)   /* can be NULL if mouse outside parent by the time we get here */
-        {
-            temp_window = fgWindowByHandle(hwnd);
-            if (temp_window && temp_window->Parent)    /* Verify we got a child window */
-                child_window = temp_window;
-        }
-    }
-    
     switch( uMsg )
     {
     case WM_CREATE:
@@ -457,11 +484,15 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
         break;
 
     case WM_SIZE:
-        /*
-         * 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.
-         */
+        /* printf("WM_SIZE (ID: %i): wParam: %i, new size: %ix%i \n",window->ID,wParam,LOWORD(lParam),HIWORD(lParam)); */
+
+        /* Update visibility state of the window */
+        if (wParam==SIZE_MINIMIZED)
+            fghUpdateWindowStatus(window,GL_FALSE);
+        else if (wParam==SIZE_RESTORED && !window->State.Visible)
+            fghUpdateWindowStatus(window,GL_TRUE);
+
+        /* Check window visible, we don't want to resize when the user or glutIconifyWindow minimized the window */
         if( window->State.Visible )
         {
             /* get old values first to compare to below */
@@ -479,29 +510,44 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
                 window->State.NeedToResize = GL_TRUE;
         }
 
+        /* according to docs, should return 0 */
+        lRet = 0;
         break;
 
     case WM_MOVE:
         {
             SFG_Window* saved_window = fgStructure.CurrentWindow;
             RECT windowRect;
-            GetWindowRect( window->Window.Handle, &windowRect );
-            
-            if (window->Parent)
+
+            /* Check window is minimized, we don't want to call the position callback when the user or glutIconifyWindow minimized the window */
+            if (!IsIconic(window->Window.Handle))
             {
-                /* For child window, we should return relative to upper-left
-                * of parent's client area.
-                */
-                POINT topleft = {windowRect.left,windowRect.top};
-
-                ScreenToClient(window->Parent->Window.Handle,&topleft);
-                windowRect.left = topleft.x;
-                windowRect.top  = topleft.y;
-            }
+                /* Get top-left of non-client area of window, matching coordinates of
+                 * glutInitPosition and glutPositionWindow, but not those of 
+                 * glutGet(GLUT_WINDOW_X) and glutGet(GLUT_WINDOW_Y), which return
+                 * top-left of client area.
+                 */
+                GetWindowRect( window->Window.Handle, &windowRect );
+            
+                if (window->Parent)
+                {
+                    /* For child window, we should return relative to upper-left
+                     * of parent's client area.
+                     */
+                    POINT topleft = {windowRect.left,windowRect.top};
 
-            INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
-            fgSetWindow(saved_window);
+                    ScreenToClient(window->Parent->Window.Handle,&topleft);
+                    windowRect.left = topleft.x;
+                    windowRect.top  = topleft.y;
+                }
+
+                INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
+                fgSetWindow(saved_window);
+            }
         }
+
+        /* according to docs, should return 0 */
+        lRet = 0;
         break;
 
     case WM_SETFOCUS:
@@ -509,31 +555,15 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
 
         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
 
-        if (child_window)
-        {
-            /* If we're dealing with a child window, make sure it has input focus instead, set it here. */
-            SetFocus(child_window->Window.Handle);
-            SetActiveWindow( child_window->Window.Handle );
-            INVOKE_WCB( *child_window, Entry, ( GLUT_ENTERED ) );
-            UpdateWindow ( child_window->Window.Handle );
-        }
-        else
-        {
-            SetActiveWindow( window->Window.Handle );
-            INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
-        }
-        /* Always request update on main window to be safe */
+        SetActiveWindow( window->Window.Handle );
         UpdateWindow ( hWnd );
 
         break;
 
     case WM_KILLFOCUS:
         {
-            SFG_Window* saved_window = fgStructure.CurrentWindow;
 /*            printf("WM_KILLFOCUS: %p\n", window ); */
             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
-            INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
-            fgSetWindow(saved_window);
 
             /* Check if there are any open menus that need to be closed */
             fgPlatformCheckMenuDeactivate();
@@ -542,6 +572,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
 
 #if 0
     case WM_ACTIVATE:
+        //printf("WM_ACTIVATE: %x (ID: %i) %d %d\n",lParam, window->ID, HIWORD(wParam), LOWORD(wParam));
         if (LOWORD(wParam) != WA_INACTIVE)
         {
 /*            printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
@@ -556,24 +587,87 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
     case WM_SETCURSOR:
 /*      printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
         if( LOWORD( lParam ) == HTCLIENT )
-            fgSetCursor ( window, window->State.Cursor ) ;
+        {
+            if (!window->State.pWState.MouseTracking)
+            {
+                TRACKMOUSEEVENT tme;
+
+                /* Cursor just entered window, set cursor look */ 
+                fgSetCursor ( window, window->State.Cursor ) ;
+
+                /* If an EntryFunc callback is specified by the user, also
+                 * invoke that callback and start mouse tracking so that
+                 * we get a WM_MOUSELEAVE message
+                 */
+                if (FETCH_WCB( *window, Entry ))
+                {
+                    SFG_Window* saved_window = fgStructure.CurrentWindow;
+                    INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
+                    fgSetWindow(saved_window);
+
+                    tme.cbSize = sizeof(TRACKMOUSEEVENT);
+                    tme.dwFlags = TME_LEAVE;
+                    tme.hwndTrack = window->Window.Handle;
+                    TrackMouseEvent(&tme);
+
+                    window->State.pWState.MouseTracking = GL_TRUE;
+                }
+            }
+        }
         else
+            /* Only pass non-client WM_SETCURSOR to DefWindowProc, or we get WM_SETCURSOR on parents of children as well */
             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
         break;
 
+    case WM_MOUSELEAVE:
+        {
+            /* NB: This message is only received when a EntryFunc callback
+             * is specified by the user, as that is the only condition under
+             * which mouse tracking is setup in WM_SETCURSOR handler above
+             */
+            SFG_Window* saved_window = fgStructure.CurrentWindow;
+            INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
+            fgSetWindow(saved_window);
+
+            window->State.pWState.MouseTracking = GL_FALSE;
+            lRet = 0;   /* As per docs, must return zero */
+        }
+        break;
+
     case WM_SHOWWINDOW:
-        window->State.Visible = GL_TRUE;
-        window->State.Redisplay = GL_TRUE;
+        /* printf("WM_SHOWWINDOW, shown? %i, source: %i\n",wParam,lParam); */
+        if (wParam)
+        {
+            fghUpdateWindowStatus(window, GL_TRUE);
+            window->State.Redisplay = GL_TRUE;
+        }
+        else
+        {
+            fghUpdateWindowStatus(window, GL_FALSE);
+            window->State.Redisplay = GL_FALSE;
+        }
         break;
 
     case WM_PAINT:
-        /* Turn on the visibility in case it was turned off somehow */
-        window->State.Visible = GL_TRUE;
-        InvalidateRect( hWnd, NULL, GL_FALSE ); /* Make sure whole window is repainted. Bit of a hack, but a safe one from what google turns up... */
-        BeginPaint( hWnd, &ps );
-        fghRedrawWindow( window );
-        EndPaint( hWnd, &ps );
-        break;
+    {
+        RECT rect;
+
+        if (GetUpdateRect(hWnd,&rect,FALSE))
+        {
+            /* As per docs, upon receiving WM_PAINT, first check if the update region is not empty before you call BeginPaint */
+            PAINTSTRUCT ps;
+
+            /* Turn on the visibility in case it was turned off somehow */
+            window->State.Visible = GL_TRUE;
+
+            InvalidateRect( hWnd, NULL, GL_FALSE );
+            BeginPaint( hWnd, &ps );
+            fghRedrawWindow( window );
+            EndPaint( hWnd, &ps );
+        }
+        lRet = 0;   /* As per docs, should return 0 */
+    }
+    break;
 
     case WM_CLOSE:
         fgDestroyWindow ( window );
@@ -589,12 +683,13 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
 
     case WM_MOUSEMOVE:
     {
+        /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
 #if defined(_WIN32_WCE)
-        window->State.MouseX = 320-HIWORD( lParam );
+        window->State.MouseX = 320-HIWORD( lParam );    /* XXX: Docs say x should be loword and y hiword? */
         window->State.MouseY = LOWORD( lParam );
 #else
-        window->State.MouseX = LOWORD( lParam );
-        window->State.MouseY = HIWORD( lParam );
+        window->State.MouseX = GET_X_LPARAM( lParam );
+        window->State.MouseY = GET_Y_LPARAM( lParam );
 #endif /* defined(_WIN32_WCE) */
         /* Restrict to [-32768, 32767] to match X11 behaviour       */
         /* See comment in "freeglut_developer" mailing list 10/4/04 */
@@ -632,12 +727,13 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
         GLboolean pressed = GL_TRUE;
         int button;
 
+        /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
 #if defined(_WIN32_WCE)
-        window->State.MouseX = 320-HIWORD( lParam );
+        window->State.MouseX = 320-HIWORD( lParam );    /* XXX: Docs say x should be loword and y hiword? */
         window->State.MouseY = LOWORD( lParam );
 #else
-        window->State.MouseX = LOWORD( lParam );
-        window->State.MouseY = HIWORD( lParam );
+        window->State.MouseX = GET_X_LPARAM( lParam );
+        window->State.MouseY = GET_Y_LPARAM( lParam );
 #endif /* defined(_WIN32_WCE) */
 
         /* Restrict to [-32768, 32767] to match X11 behaviour       */
@@ -700,17 +796,20 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
                                window->State.MouseX, window->State.MouseY ) )
             break;
 
-        /* Set capture so that the window captures all the mouse messages */
-        /*
-         * XXX - Multiple button support:  Under X11, the mouse is not released
-         * XXX - from the window until all buttons have been released, even if the
-         * XXX - user presses a button in another window.  This will take more
-         * XXX - code changes than I am up to at the moment (10/5/04).  The present
-         * XXX - is a 90 percent solution.
+        /* Set capture so that the window captures all the mouse messages
+         *
+         * The mouse is not released from the window until all buttons have
+         * been released, even if the user presses a button in another window.
+         * This is consistent with the behavior on X11.
          */
         if ( pressed == GL_TRUE )
-          SetCapture ( window->Window.Handle ) ;
-        else
+        {
+            if (!setCaptureActive)
+                SetCapture ( window->Window.Handle ) ;
+            setCaptureActive = 1; /* Set to false in WM_CAPTURECHANGED handler */
+        }
+        else if (!GetAsyncKeyState(VK_LBUTTON) && !GetAsyncKeyState(VK_MBUTTON) && !GetAsyncKeyState(VK_RBUTTON))
+          /* Make sure all mouse buttons are released before releasing capture */
           ReleaseCapture () ;
 
         if( ! FETCH_WCB( *window, Mouse ) )
@@ -729,15 +828,34 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
         );
 
         fgState.Modifiers = INVALID_MODIFIERS;
+
+        /* As per docs, should return zero */
+        lRet = 0;
     }
     break;
 
     case WM_MOUSEWHEEL:
     {
-        int wheel_number = LOWORD( wParam );
-        short ticks = ( short )HIWORD( wParam );
-               fgState.MouseWheelTicks += ticks;
+        int wheel_number = 0;   /* Only one scroll wheel on windows */
+#if defined(_WIN32_WCE)
+        int modkeys = LOWORD(wParam); 
+        short ticks = (short)HIWORD(wParam);
+        /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
+        xPos = LOWORD(lParam);  -- straight from docs, not consistent with mouse nutton and mouse motion above (which i think is wrong)
+        yPos = HIWORD(lParam);
+        */
+#else
+        /* int modkeys = GET_KEYSTATE_WPARAM( wParam ); */
+        short ticks = GET_WHEEL_DELTA_WPARAM( wParam );
+        /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
+        window->State.MouseX = GET_X_LPARAM( lParam );
+        window->State.MouseY = GET_Y_LPARAM( lParam );
+        */
+#endif /* defined(_WIN32_WCE) */
+
+        window = fghWindowUnderCursor(window);
 
+               fgState.MouseWheelTicks += ticks;
         if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
                {
                        int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
@@ -786,28 +904,31 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
 
             fgState.Modifiers = INVALID_MODIFIERS;
                }
+        /* Per docs, should return zero */
+        lRet = 0;
     }
     break ;
 
     case WM_SYSKEYDOWN:
     case WM_KEYDOWN:
-        if (child_window)
-            window = child_window;
-        lRet = fghKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
+    {
+        window = fghWindowUnderCursor(window);
+        lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
+    }
     break;
 
     case WM_SYSKEYUP:
     case WM_KEYUP:
-        if (child_window)
-            window = child_window;
-        lRet = fghKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
+    {
+        window = fghWindowUnderCursor(window);
+        lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
+    }
     break;
 
     case WM_SYSCHAR:
     case WM_CHAR:
     {
-      if (child_window)
-        window = child_window;
+      window = fghWindowUnderCursor(window);
 
       if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
             break;
@@ -822,34 +943,13 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
     break;
 
     case WM_CAPTURECHANGED:
-        /* User has finished resizing the window, force a redraw */
-        INVOKE_WCB( *window, Display, ( ) );
-
-        /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
-        break;
-
-        /* Other messages that I have seen and which are not handled already */
-    case WM_SETTEXT:  /* 0x000c */
-        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
-        /* Pass it on to "DefWindowProc" to set the window text */
-        break;
-
-    case WM_GETTEXT:  /* 0x000d */
-        /* Ideally we would copy the title of the window into "lParam" */
-        /* strncpy ( (char *)lParam, "Window Title", wParam );
-           lRet = ( wParam > 12 ) ? 12 : wParam;  */
-        /* the number of characters copied */
-        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
-        break;
-
-    case WM_GETTEXTLENGTH:  /* 0x000e */
-        /* Ideally we would get the length of the title of the window */
-        lRet = 12;
-        /* the number of characters in "Window Title\0" (see above) */
-        break;
-
-    case WM_ERASEBKGND:  /* 0x0014 */
-        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+        if (!lParam || !fgWindowByHandle((HWND)lParam))
+            /* Capture released or capture taken by non-FreeGLUT window */
+            setCaptureActive = 0;
+        /* Docs advise a redraw */
+        InvalidateRect( hWnd, NULL, GL_FALSE );
+        UpdateWindow(hWnd);
+        lRet = 0;   /* Per docs, should return zero */
         break;
 
 #if !defined(_WIN32_WCE)
@@ -860,12 +960,6 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
         /* Help screen says this message must be passed to "DefWindowProc" */
         break;
 
-    case WM_NCPAINT:  /* 0x0085 */
-      /* Need to update the border of this window */
-        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
-        /* Pass it on to "DefWindowProc" to repaint a standard border */
-        break;
-
     case WM_SYSCOMMAND :  /* 0x0112 */
         {
           /*
@@ -888,8 +982,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
 
             case SC_MINIMIZE   :
                 /* User has clicked on the "-" to minimize the window */
-                /* Turn off the visibility */
-                window->State.Visible = GL_FALSE ;
+                /* Turning off the visibility is handled in WM_SIZE handler */
 
                 break ;