Takeshi Nishimura\'s changes to make the Windows mouse wheel/button mapping match...
[freeglut] / src / freeglut_main.c
index d464ca4..7f62b84 100644 (file)
 #include "freeglut_internal.h"
 #include <errno.h>
 #include <stdarg.h>
-#if HAVE_VPRINTF
+#if TARGET_HOST_WIN32
 #    define VFPRINTF(s,f,a) vfprintf((s),(f),(a))
-#elif HAVE_DOPRNT
-#    define VFPRINTF(s,f,a) _doprnt((f),(a),(s))
 #else
-#    define VFPRINTF(s,f,a)
+#    if HAVE_VPRINTF
+#        define VFPRINTF(s,f,a) vfprintf((s),(f),(a))
+#    elif HAVE_DOPRNT
+#        define VFPRINTF(s,f,a) _doprnt((f),(a),(s))
+#    else
+#        define VFPRINTF(s,f,a)
+#    endif
 #endif
 
 #if TARGET_HOST_WINCE
@@ -89,7 +93,7 @@ struct GXKeyList gxKeyList;
  */
 static void fghReshapeWindow ( SFG_Window *window, int width, int height )
 {
-    SFG_Window *current_window = fgStructure.Window;
+    SFG_Window *current_window = fgStructure.CurrentWindow;
 
     freeglut_return_if_fail( window != NULL );
 
@@ -100,9 +104,7 @@ static void fghReshapeWindow ( SFG_Window *window, int width, int height )
                    width, height );
     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
 
-#elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
-
-#if !TARGET_HOST_WINCE
+#elif TARGET_HOST_WIN32
     {
         RECT winRect;
         int x, y, w, h;
@@ -152,7 +154,7 @@ static void fghReshapeWindow ( SFG_Window *window, int width, int height )
                       SWP_NOZORDER
         );
     }
-#endif /* TARGET_HOST_WINCE */
+#endif
 
     /*
      * XXX Should update {window->State.OldWidth, window->State.OldHeight}
@@ -166,8 +168,6 @@ static void fghReshapeWindow ( SFG_Window *window, int width, int height )
         glViewport( 0, 0, width, height );
     }
 
-#endif
-
     /*
      * Force a window redraw.  In Windows at least this is only a partial
      * solution:  if the window is increasing in size in either dimension,
@@ -187,7 +187,7 @@ static void fghReshapeWindow ( SFG_Window *window, int width, int height )
  */
 static void fghRedrawWindow ( SFG_Window *window )
 {
-    SFG_Window *current_window = fgStructure.Window;
+    SFG_Window *current_window = fgStructure.CurrentWindow;
 
     freeglut_return_if_fail( window );
     freeglut_return_if_fail( FETCH_WCB ( *window, Display ) );
@@ -458,7 +458,7 @@ static void fghSleepForEvents( void )
     msec = fghNextTimer( );
     /* XXX Use GLUT timers for joysticks... */
     /* XXX Dumb; forces granularity to .01sec */
-    if( fghHaveJoystick( ) && ( msec < 10 ) )     
+    if( fghHaveJoystick( ) && ( msec > 10 ) )     
         msec = 10;
 
 #if TARGET_HOST_UNIX_X11
@@ -588,6 +588,8 @@ void FGAPIENTRY glutMainLoopEvent( void )
                 if( ( width != window->State.OldWidth ) ||
                     ( height != window->State.OldHeight ) )
                 {
+                    SFG_Window *current_window = fgStructure.CurrentWindow;
+
                     window->State.OldWidth = width;
                     window->State.OldHeight = height;
                     if( FETCH_WCB( *window, Reshape ) )
@@ -598,6 +600,8 @@ void FGAPIENTRY glutMainLoopEvent( void )
                         glViewport( 0, 0, width, height );
                     }
                     glutPostRedisplay( );
+                    if( window->IsMenu )
+                        fgSetWindow( current_window );
                 }
             }
             break;
@@ -624,8 +628,7 @@ void FGAPIENTRY glutMainLoopEvent( void )
             if( event.xexpose.count == 0 )
             {
                 GETWINDOW( xexpose );
-                fgSetWindow( window );
-                glutPostRedisplay( );
+                window->State.Redisplay = GL_TRUE;
             }
             break;
 
@@ -691,6 +694,10 @@ void FGAPIENTRY glutMainLoopEvent( void )
         case LeaveNotify:
             GETWINDOW( xcrossing );
             GETMOUSE( xcrossing );
+            if( ( event.type == LeaveNotify ) && window->IsMenu &&
+                window->ActiveMenu && window->ActiveMenu->IsActive )
+                fgUpdateMenuHighlight( window->ActiveMenu );
+
             INVOKE_WCB( *window, Entry, ( ( EnterNotify == event.type ) ?
                                           GLUT_ENTERED :
                                           GLUT_LEFT ) );
@@ -710,8 +717,8 @@ void FGAPIENTRY glutMainLoopEvent( void )
                     window->ActiveMenu->Window->State.MouseY =
                         event.xmotion.y_root - window->ActiveMenu->Y;
                 }
-                window->ActiveMenu->Window->State.Redisplay = GL_TRUE ;
-                fgSetWindow( window->ActiveMenu->ParentWindow );
+
+                fgUpdateMenuHighlight( window->ActiveMenu );
 
                 break;
             }
@@ -777,12 +784,8 @@ void FGAPIENTRY glutMainLoopEvent( void )
 
             fgState.Modifiers = fghGetXModifiers( &event );
 
-            /*
-             * Finally execute the mouse or mouse wheel callback
-             *
-             * XXX Use a symbolic constant, *not* "4"!  ("3, sire!")
-             */
-            if( ( button < 3 ) || ( ! FETCH_WCB( *window, MouseWheel ) ) )
+            /* Finally execute the mouse or mouse wheel callback */
+            if( ( button < glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS ) ) || ( ! FETCH_WCB( *window, MouseWheel ) ) )
                 INVOKE_WCB( *window, Mouse, ( button,
                                               pressed ? GLUT_DOWN : GLUT_UP,
                                               event.xbutton.x,
@@ -802,7 +805,7 @@ void FGAPIENTRY glutMainLoopEvent( void )
                  * XXX Note that {button} has already been decremeted
                  * XXX in mapping from X button numbering to GLUT.
                  */
-                int wheel_number = (button - 3) / 2;
+                int wheel_number = (button - glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS )) / 2;
                 int direction = -1;
                 if( button % 2 )
                     direction = 1;
@@ -862,13 +865,13 @@ void FGAPIENTRY glutMainLoopEvent( void )
 
             if( event.type == KeyPress )
             {
-                keyboard_cb = FETCH_WCB( *window, Keyboard );
-                special_cb  = FETCH_WCB( *window, Special  );
+                keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard ));
+                special_cb  = (FGCBSpecial) ( FETCH_WCB( *window, Special  ));
             }
             else
             {
-                keyboard_cb = FETCH_WCB( *window, KeyboardUp );
-                special_cb  = FETCH_WCB( *window, SpecialUp  );
+                keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp ));
+                special_cb  = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp  ));
             }
 
             /* Is there a keyboard/special callback hooked for this window? */
@@ -1025,7 +1028,7 @@ void FGAPIENTRY glutMainLoop( void )
     {
         if ( FETCH_WCB( *window, Visibility ) )
         {
-            SFG_Window *current_window = fgStructure.Window ;
+            SFG_Window *current_window = fgStructure.CurrentWindow ;
 
             INVOKE_WCB( *window, Visibility, ( window->State.Visible ) );
             fgSetWindow( current_window );
@@ -1056,7 +1059,13 @@ void FGAPIENTRY glutMainLoop( void )
         else
         {
             if( fgState.IdleCallback )
+            {
+                if( fgStructure.CurrentWindow &&
+                    fgStructure.CurrentWindow->IsMenu )
+                    /* fail safe */
+                    fgSetWindow( window );
                 fgState.IdleCallback( );
+            }
 
             fghSleepForEvents( );
         }
@@ -1223,27 +1232,19 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
     case WM_ACTIVATE:
         if (LOWORD(wParam) != WA_INACTIVE)
         {
-/*            printf("WM_ACTIVATE: glutSetCursor( %p, %d)\n", window,
+/*            printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
                    window->State.Cursor ); */
-            glutSetCursor( window->State.Cursor );
+            fgSetCursor( window, window->State.Cursor );
         }
 
         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
         break;
 #endif
 
-        /*
-         * 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 glutSetCursor() instead of defining two macros
-         * XXX and implementing a nested case in-line.
-         */
     case WM_SETCURSOR:
 /*      printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
         if( LOWORD( lParam ) == HTCLIENT )
-            glutSetCursor ( window->State.Cursor ) ;
+            fgSetCursor ( window, window->State.Cursor ) ;
         else
             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
         break;
@@ -1273,6 +1274,20 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
          */
         return 0;
 
+    /* XXX For a future patch:  we need a mouse entry event.  Unfortunately Windows
+     * XXX doesn't give us one, so we will probably need a "MouseInWindow" flag in
+     * XXX the SFG_Window structure.  Set it to true to begin with and then have the
+     * XXX WM_MOUSELEAVE code set it to false.  Then when we get a WM_MOUSEMOVE event,
+     * XXX if the flag is false we invoke the Entry callback and set the flag to true.
+     */
+    case 0x02a2:  /* This is the message we get when the mouse is leaving the window */
+        if( window->IsMenu &&
+            window->ActiveMenu && window->ActiveMenu->IsActive )
+            fgUpdateMenuHighlight( window->ActiveMenu );
+
+        INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
+        break ;
+
     case WM_MOUSEMOVE:
     {
 #if TARGET_HOST_WINCE
@@ -1289,8 +1304,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
 
         if ( window->ActiveMenu )
         {
-            window->State.Redisplay = GL_TRUE;
-            fgSetWindow ( window->ActiveMenu->ParentWindow );
+            fgUpdateMenuHighlight( window->ActiveMenu );
             break;
         }
 
@@ -1387,15 +1401,6 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
                                window->State.MouseX, window->State.MouseY ) )
             break;
 
-        if( window->Menu[ button ] && pressed )
-        {
-            window->State.Redisplay = GL_TRUE;
-            fgSetWindow( window );
-            fgActivateMenu( window, button );
-
-            break;
-        }
-
         /* Set capture so that the window captures all the mouse messages */
         /*
          * XXX - Multiple button support:  Under X11, the mouse is not released
@@ -1472,11 +1477,14 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
             else  /* No mouse wheel, call the mouse button callback twice */
             {
                 /*
+                 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
+                 *  "    "   one                     +1 to 5, -1 to 6, ...
+                 *
                  * XXX The below assumes that you have no more than 3 mouse
                  * XXX buttons.  Sorry.
                  */
-                int button = wheel_number*2 + 4;
-                if( direction > 0 )
+                int button = wheel_number * 2 + 3;
+                if( direction < 0 )
                     ++button;
                 INVOKE_WCB( *window, Mouse,
                             ( button, GLUT_DOWN,
@@ -1484,7 +1492,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
                 );
                 INVOKE_WCB( *window, Mouse,
                             ( button, GLUT_UP,
-                              window->State.MouseX, window->State.MouseX )
+                              window->State.MouseX, window->State.MouseY )
                 );
             }