No need to handle WM_CANCELMODE, defwindowproc takes care of it
[freeglut] / src / mswin / fg_main_mswin.c
index daa611c..bf02a7e 100644 (file)
@@ -361,6 +361,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
 {
     SFG_Window *window;
     LRESULT lRet = 1;
+    static int setCaptureActive = 0;
 
     FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
 
@@ -554,16 +555,24 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
             {
                 TRACKMOUSEEVENT tme;
 
-                /* Cursor just entered window, set cursor look, invoke callback and start tracking so that we get a WM_MOUSELEAVE message */
+                /* Cursor just entered window, set cursor look */ 
                 fgSetCursor ( window, window->State.Cursor ) ;
-                INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
 
-                tme.cbSize = sizeof(TRACKMOUSEEVENT);
-                tme.dwFlags = TME_LEAVE;
-                tme.hwndTrack = window->Window.Handle;
-                TrackMouseEvent(&tme);
-
-                window->State.pWState.MouseTracking = GL_TRUE;
+                /* 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 ))
+                {
+                    INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
+
+                    tme.cbSize = sizeof(TRACKMOUSEEVENT);
+                    tme.dwFlags = TME_LEAVE;
+                    tme.hwndTrack = window->Window.Handle;
+                    TrackMouseEvent(&tme);
+
+                    window->State.pWState.MouseTracking = GL_TRUE;
+                }
             }
         }
         else
@@ -573,6 +582,10 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
 
     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);
@@ -724,17 +737,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 ) )
@@ -753,6 +769,9 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
         );
 
         fgState.Modifiers = INVALID_MODIFIERS;
+
+        /* As per docs, should return zero */
+        lRet = 0;
     }
     break;
 
@@ -850,6 +869,9 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
     break;
 
     case WM_CAPTURECHANGED:
+        if (!lParam || !fgWindowByHandle((HWND)lParam))
+            /* Capture released or capture taken by non-FreeGLUT window */
+            setCaptureActive = 0;
         /* User has finished resizing the window, force a redraw */
         INVOKE_WCB( *window, Display, ( ) );
         lRet = 0;   /* Per docs, should return zero */