can now also handle the case where menus is opened, client area of
authorDiederick Niehorster <dcnieho@gmail.com>
Sat, 21 Jul 2012 04:04:45 +0000 (04:04 +0000)
committerDiederick Niehorster <dcnieho@gmail.com>
Sat, 21 Jul 2012 04:04:45 +0000 (04:04 +0000)
window with menu is clicked and then user switches to another window.

Implemented menu enumerator and a function for getting currently active
menu, if any

git-svn-id: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@1354 7f0cb862-5218-0410-a997-914c9d46530a

src/fg_internal.h
src/fg_menu.c
src/fg_structure.c
src/mswin/fg_main_mswin.c

index 13e57a3..61ae5ce 100644 (file)
@@ -661,7 +661,8 @@ struct tagSFG_Enumerator
     GLboolean   found;                          /* Used to terminate search  */
     void*       data;                           /* Custom data pointer       */
 };
-typedef void (* FGCBenumerator  )( SFG_Window *, SFG_Enumerator * );
+typedef void (* FGCBWindowEnumerator  )( SFG_Window *, SFG_Enumerator * );
+typedef void (* FGCBMenuEnumerator  )( SFG_Menu *, SFG_Enumerator * );
 
 /* The bitmap font structure */
 typedef struct tagSFG_Font SFG_Font;
@@ -915,8 +916,8 @@ void fgSetCursor ( SFG_Window *window, int cursorID );
  * and userData is the a custom user-supplied pointer. Functions
  * are defined and exported from freeglut_structure.c file.
  */
-void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator );
-void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback,
+void fgEnumWindows( FGCBWindowEnumerator enumCallback, SFG_Enumerator* enumerator );
+void fgEnumSubWindows( SFG_Window* window, FGCBWindowEnumerator enumCallback,
                        SFG_Enumerator* enumerator );
 
 /*
@@ -940,6 +941,12 @@ SFG_Window* fgWindowByID( int windowID );
 SFG_Menu* fgMenuByID( int menuID );
 
 /*
+ * Returns active menu, if any. Assumption: only one menu active throughout application at any one time.
+ * This is easier than fgWindowByXXX as all menus are placed in one doubly linked list...
+ */
+SFG_Menu* fgGetActiveMenu( );
+
+/*
  * The menu activation and deactivation the code. This is the meat
  * of the menu user interface handling code...
  */
index 2460b1d..0c6c64e 100644 (file)
@@ -512,7 +512,7 @@ static void fghActivateMenu( SFG_Window* window, int button )
     SFG_Menu* menu = window->Menu[ button ];
     SFG_Window* current_window = fgStructure.CurrentWindow;
 
-    /* If the menu is already active in another window, deactivate it (and any submenu's) there */
+    /* If the menu is already active in another window, deactivate it (and any submenus) there */
     if ( menu->ParentWindow )
       fgDeactivateMenu(menu->ParentWindow);
 
index 1e05653..7c2c143 100644 (file)
@@ -378,7 +378,7 @@ void fgDestroyStructure( void )
 /*
  * Helper function to enumerate through all registered top-level windows
  */
-void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator )
+void fgEnumWindows( FGCBWindowEnumerator enumCallback, SFG_Enumerator* enumerator )
 {
     SFG_Window *window;
 
@@ -398,10 +398,32 @@ void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator )
 }
 
 /*
+* Helper function to enumerate through all registered top-level windows
+*/
+void fgEnumMenus( FGCBMenuEnumerator enumCallback, SFG_Enumerator* enumerator )
+{
+    SFG_Menu *menu;
+
+    FREEGLUT_INTERNAL_ERROR_EXIT ( enumCallback && enumerator,
+        "Enumerator or callback missing from window enumerator call",
+        "fgEnumWindows" );
+
+    /* It's enough to check all entries in fgStructure.Menus... */
+    for( menu = (SFG_Menu *)fgStructure.Menus.First;
+        menu;
+        menu = (SFG_Menu *)menu->Node.Next )
+    {
+        enumCallback( menu, enumerator );
+        if( enumerator->found )
+            return;
+    }
+}
+
+/*
  * Helper function to enumerate through all a window's subwindows
  * (single level descent)
  */
-void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback,
+void fgEnumSubWindows( SFG_Window* window, FGCBWindowEnumerator enumCallback,
                        SFG_Enumerator* enumerator )
 {
     SFG_Window *child;
@@ -485,7 +507,7 @@ static void fghcbWindowByID( SFG_Window *window, SFG_Enumerator *enumerator )
 }
 
 /*
- * This function is similiar to the previous one, except it is
+ * This function is similar to the previous one, except it is
  * looking for a specified (sub)window identifier. The function
  * is defined in freeglut_structure.c file.
  */
@@ -493,7 +515,7 @@ SFG_Window* fgWindowByID( int windowID )
 {
     SFG_Enumerator enumerator;
 
-    /* Uses a method very similiar for fgWindowByHandle... */
+    /* Uses a method very similar for fgWindowByHandle... */
     enumerator.found = GL_FALSE;
     enumerator.data = ( void * )&windowID;
     fgEnumWindows( fghcbWindowByID, &enumerator );
@@ -503,19 +525,77 @@ SFG_Window* fgWindowByID( int windowID )
 }
 
 /*
- * Looks up a menu given its ID. This is easier that fgWindowByXXX
+ * A static helper function to look for a menu given its ID
+ */
+static void fghcbMenuByID( SFG_Menu *menu,
+    SFG_Enumerator *enumerator )
+{
+    if ( enumerator->found )
+        return;
+
+    /* Check the menu's ID. */
+    if( menu->ID == (int)(enumerator->data) )
+    {
+        enumerator->found = GL_TRUE;
+        enumerator->data = menu;
+
+        return;
+    }
+}
+
+/*
+ * Looks up a menu given its ID. This is easier than fgWindowByXXX
  * as all menus are placed in one doubly linked list...
  */
 SFG_Menu* fgMenuByID( int menuID )
 {
-    SFG_Menu *menu = NULL;
+    SFG_Enumerator enumerator;
+
+    /* This is easy and makes use of the menus enumeration defined above */
+    enumerator.found = GL_FALSE;
+    enumerator.data = (void *)menuID;
+    fgEnumMenus( fghcbMenuByID, &enumerator );
+
+    if( enumerator.found )
+        return( SFG_Menu *) enumerator.data;
+
+    return NULL;
+}
+
+/*
+ * A static helper function to look for an active menu
+ */
+static void fghcbGetActiveMenu( SFG_Menu *menu,
+    SFG_Enumerator *enumerator )
+{
+    if ( enumerator->found )
+        return;
+
+    /* Check the menu's ID. */
+    if( menu->IsActive )
+    {
+        enumerator->found = GL_TRUE;
+        enumerator->data = menu;
+
+        return;
+    }
+}
+
+/*
+ * Returns active menu, if any. Assumption: only one menu active throughout application at any one time.
+ * This is easier than fgWindowByXXX as all menus are placed in one doubly linked list...
+ */
+SFG_Menu* fgGetActiveMenu( )
+{
+    SFG_Enumerator enumerator;
+
+    /* This is easy and makes use of the menus enumeration defined above */
+    enumerator.found = GL_FALSE;
+    fgEnumMenus( fghcbGetActiveMenu, &enumerator );
+
+    if( enumerator.found )
+        return( SFG_Menu *) enumerator.data;
 
-    /* It's enough to check all entries in fgStructure.Menus... */
-    for( menu = (SFG_Menu *)fgStructure.Menus.First;
-         menu;
-         menu = (SFG_Menu *)menu->Node.Next )
-        if( menu->ID == menuID )
-            return menu;
     return NULL;
 }
 
index c72e467..a992b2b 100644 (file)
@@ -493,34 +493,39 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
         break;
 
     case WM_KILLFOCUS:
-/*        printf("WM_KILLFOCUS (ismenu: %i): %p\n", window->IsMenu, window ); */
-        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
-        INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
-
-        /* If this is a menu that lost focus, see if user either switched
-           application or FreeGLUT window (if one is running multiple
-           windows). If so, close menu that lost focus.
-         */
-        if( window->IsMenu &&
-            window->ActiveMenu && window->ActiveMenu->IsActive )
         {
-            SFG_Window* wnd = NULL;
-            HWND hwnd = GetForegroundWindow();  /* Get window with current focus */
-            if (hwnd)
-                /* See if its one of our windows */
-                wnd = fgWindowByHandle(hwnd);
-
-            if (!hwnd || !wnd)
-                /* User switched to another application*/
-                fgDeactivateMenu(window->ActiveMenu->ParentWindow);
-            else if (
-                ( wnd->IsMenu && wnd->ActiveMenu->ParentWindow!=window->ActiveMenu->ParentWindow) ||    /* Make sure we don't kill the menu when trying to enter a submenu */
-                (!wnd->IsMenu && wnd!=window->ActiveMenu->ParentWindow)
-                )
-                /* User switched to another FreeGLUT window */
-                fgDeactivateMenu(window->ActiveMenu->ParentWindow);
-        }
+            SFG_Menu* menu = NULL;
+/*            printf("WM_KILLFOCUS (ismenu: %i): %p\n", window->IsMenu, window ); */
+            lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+            INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
 
+            /* 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.
+             */
+            if ( fgStructure.CurrentMenu )
+                menu = fgGetActiveMenu();
+            
+            if ( menu )
+            {
+                SFG_Window* wnd = NULL;
+                HWND hwnd = GetForegroundWindow();  /* Get window with current focus */
+                if (hwnd)
+                    /* See if its one of our windows */
+                    wnd = fgWindowByHandle(hwnd);
+
+                if (!hwnd || !wnd)
+                    /* User switched to another application*/
+                    fgDeactivateMenu(menu->ParentWindow);
+                else if (
+                    ( wnd->IsMenu && wnd->ActiveMenu && wnd->ActiveMenu->ParentWindow!=menu->ParentWindow) ||    /* Make sure we don't kill the menu when trying to enter a submenu */
+                    (!wnd->IsMenu && wnd!=menu->ParentWindow)
+                    )
+                    /* User switched to another FreeGLUT window */
+                    fgDeactivateMenu(menu->ParentWindow);
+            }
+        }
         break;
 
 #if 0