From 91cac2f34bfc430f6a68ea950cc8f5169327b794 Mon Sep 17 00:00:00 2001 From: Diederick Niehorster Date: Thu, 16 Oct 2014 17:43:22 +0000 Subject: [PATCH] be more careful about closing menus when focus changes. Only do so when new focus window is not ANY of the open menus and when it is not the menu's parent window (all open menus are guaranteed to have the same parent in my reading of the code) Also simplified situation in which menus are SW_SHOWed... if a gamemode window is open, it must the parent of any active windows as there can be no other windows open on top of the gamemode window. git-svn-id: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@1716 7f0cb862-5218-0410-a997-914c9d46530a --- src/fg_structure.c | 3 ++- src/mswin/fg_main_mswin.c | 4 ++-- src/mswin/fg_menu_mswin.c | 56 +++++++++++++++++++++++++++++++++++++-------- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/fg_structure.c b/src/fg_structure.c index 2a65b69..8e1b966 100644 --- a/src/fg_structure.c +++ b/src/fg_structure.c @@ -568,7 +568,7 @@ static void fghcbGetActiveMenu( SFG_Menu *menu, if ( enumerator->found ) return; - /* Check the menu's ID. */ + /* Check the menu's is active */ if( menu->IsActive ) { enumerator->found = GL_TRUE; @@ -580,6 +580,7 @@ static void fghcbGetActiveMenu( SFG_Menu *menu, /* * Returns active menu, if any. Assumption: only one menu active throughout application at any one time. + * This is false when a submenu is also open. * This is easier than fgWindowByXXX as all menus are placed in one doubly linked list... */ SFG_Menu* fgGetActiveMenu( ) diff --git a/src/mswin/fg_main_mswin.c b/src/mswin/fg_main_mswin.c index 137fc06..55280f1 100644 --- a/src/mswin/fg_main_mswin.c +++ b/src/mswin/fg_main_mswin.c @@ -1759,8 +1759,8 @@ void fgPlatformVisibilityWork(SFG_Window* window) win = win->Parent; break; case DesireNormalState: - if (win->IsMenu && (!fgStructure.GameModeWindow || win->ActiveMenu->ParentWindow != fgStructure.GameModeWindow)) - cmdShow = SW_SHOWNA; /* Just show, don't activate window if its a menu. Only exception is when the parent is a gamemode window as the menu would pop under it when we do this... */ + if (win->IsMenu && !fgStructure.GameModeWindow) + cmdShow = SW_SHOWNA; /* Just show, don't activate window if its a menu. Only exception is when there is a gamemode window as the menu would pop under it when we do this... */ else cmdShow = SW_SHOW; break; diff --git a/src/mswin/fg_menu_mswin.c b/src/mswin/fg_menu_mswin.c index 93c538e..33b59ba 100644 --- a/src/mswin/fg_menu_mswin.c +++ b/src/mswin/fg_menu_mswin.c @@ -30,6 +30,9 @@ #include "../fg_internal.h" +extern void fgEnumMenus( FGCBMenuEnumerator enumCallback, SFG_Enumerator* enumerator ); + + GLvoid fgPlatformGetGameModeVMaxExtent( SFG_Window* window, int* x, int* y ) { @@ -37,24 +40,59 @@ GLvoid fgPlatformGetGameModeVMaxExtent( SFG_Window* window, int* x, int* y ) *y = glutGet ( GLUT_SCREEN_HEIGHT ); } +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) { /* 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 ( fgState.ActiveMenus ) - menu = fgGetActiveMenu(); - - if ( menu ) { - if (newFocusWnd != menu->Window->Window.Handle) - /* When in GameMode, the menu's parent window will lose focus when the menu is opened. - * This is sadly necessary as we need to do an activating ShowWindow() for the menu - * to pop up over the gamemode window - */ - fgDeactivateMenu(menu->ParentWindow); + /* 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 ) + { + /* 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) + { + /* focus shifted to another window than the menu's parent, close menus */ + fgDeactivateMenu(menu->ParentWindow); + return; + } + } } }; -- 1.7.10.4