Added "hack" function for glutCreateMenuUcall
[freeglut] / src / mswin / fg_menu_mswin.c
index 3d83693..42d056b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * freeglut_menu_mswin.c
+ * fg_menu_mswin.c
  *
  * The Windows-specific mouse cursor related stuff.
  *
@@ -29,7 +29,9 @@
 #include <GL/freeglut.h>
 #include "../fg_internal.h"
 
-extern void fghGetClientArea( RECT *clientRect, const SFG_Window *window, BOOL wantPosOutside );
+
+extern void fgEnumMenus( FGCBMenuEnumerator enumCallback, SFG_Enumerator* enumerator );
+
 
 
 GLvoid fgPlatformGetGameModeVMaxExtent( SFG_Window* window, int* x, int* y )
@@ -38,46 +40,57 @@ GLvoid fgPlatformGetGameModeVMaxExtent( SFG_Window* window, int* x, int* y )
     *y = glutGet ( GLUT_SCREEN_HEIGHT );
 }
 
-void fgPlatformCheckMenuDeactivate()
+static void fghcbIsActiveMenu(SFG_Menu *menu,
+    SFG_Enumerator *enumerator)
+{
+    if (enumerator->found)
+        return;
+
+    /* Check the menu's active and the one we are searching for. */
+    if (menu->IsActive && menu->Window->Window.Handle==(HWND)enumerator->data)
+    {
+        enumerator->found = GL_TRUE;
+        enumerator->data  = (void*) menu;
+        return;
+    }
+}
+
+void fgPlatformCheckMenuDeactivate(HWND newFocusWnd)
 {
-    /* If we have an open menu, see if the open menu should be closed
-     * when focus was lost because user either switched
-     * application or FreeGLUT window (if one is running multiple
-     * windows). If so, close menu the active menu.
+    /* User/system switched application focus.
+     * If we have an open menu, close it.
+     * If the window that got focus is an active
+     * menu window, don't do anything. This occurs
+     * as it is sadly necessary to do an activating
+     * ShowWindow() for the menu to pop up over the
+     * gamemode window.
+     * If the window that got focus is the gamemode
+     * window, the menus pop under it. Bring them
+     * back in view in this special case.
      */
     SFG_Menu* menu = NULL;
+    SFG_Enumerator enumerator;
 
-    if ( fgStructure.Menus.First )
-        menu = fgGetActiveMenu();
-
-    if ( menu )
+    if ( fgState.ActiveMenus )
     {
-        SFG_Window* wnd = NULL;
-        HWND hwnd = GetFocus();  /* Get window with current focus - NULL for non freeglut windows */
-        if (hwnd)
-            /* See which of our windows it is */
-            wnd = fgWindowByHandle(hwnd);
-
-        if (!hwnd || !wnd)
-            /* User switched to another application*/
-            fgDeactivateMenu(menu->ParentWindow);
-        else if (!wnd->IsMenu)      /* Make sure we don't kill the menu when trying to enter a submenu */
+        /* see if there is an active menu whose window matches the one that got focus */
+        enumerator.found = GL_FALSE;
+        enumerator.data  = (void*) newFocusWnd;
+        fgEnumMenus(fghcbIsActiveMenu, &enumerator);
+        if (enumerator.found)
+            menu = (SFG_Menu*) enumerator.data;
+
+        if ( !menu )
         {
-            if (wnd!=menu->ParentWindow)
-                /* User switched to another FreeGLUT window */
-                fgDeactivateMenu(menu->ParentWindow);
-            else
+            /* window that got focus was not one of the active menus. That means we'll
+             * close the active menu's unless the window that got focus was their parent */
+            menu = fgGetActiveMenu();
+            
+            if (newFocusWnd != menu->ParentWindow->Window.Handle)
             {
-                /* Check if focus lost because non-client area of
-                 * window was pressed (pressing on client area is
-                 * handled in fgCheckActiveMenu)
-                 */
-                POINT mouse_pos;
-                RECT clientArea;
-                fghGetClientArea(&clientArea,menu->ParentWindow, GL_FALSE);
-                GetCursorPos(&mouse_pos);
-                if ( !PtInRect( &clientArea, mouse_pos ) )
-                    fgDeactivateMenu(menu->ParentWindow);
+                /* focus shifted to another window than the menu's parent, close menus */
+                fgDeactivateMenu(menu->ParentWindow);
+                return;
             }
         }
     }
@@ -93,3 +106,8 @@ int FGAPIENTRY __glutCreateMenuWithExit( void(* callback)( int ), void (__cdecl
   return glutCreateMenu( callback );
 }
 
+int FGAPIENTRY __glutCreateMenuUcallWithExit(void(*callback)(int, void*), void(__cdecl *exit_function)(int), void* user_data)
+{
+       __glutExitFunc = exit_function;
+       return glutCreateMenuUcall(callback, user_data);
+}