From John Scipione <jscipione@xxxxxxxxx>:
John Scipione has uploaded this change for review. (
https://review.haiku-os.org/c/haiku/+/2289 ;)
Change subject: BPopUpMenu: Call MenusBeginning() and MenusEnded() hook methods
......................................................................
BPopUpMenu: Call MenusBeginning() and MenusEnded() hook methods
... when opening and closing a BPopUpMenu that isn't attached to a BMenuBar
asynchronously. Check to see if we are attached to a BMenuBar first because
if we are attached to a BMenuBar (as is the case for example in a BMenuField)
the BMenuBar will call MenusBeginning() and MenuEnding() for us. Create
private static class method _HasMenuBar() for this purpose.
Update documentation for BWindow::MenusBeginning() and BWindow::MenusEnded().
---
M docs/user/interface/Window.dox
M headers/os/interface/PopUpMenu.h
M src/kits/interface/PopUpMenu.cpp
3 files changed, 48 insertions(+), 10 deletions(-)
git pull ssh://git.haiku-os.org:22/haiku refs/changes/89/2289/1
diff --git a/docs/user/interface/Window.dox b/docs/user/interface/Window.dox
index 89f0960..8886305 100644
--- a/docs/user/interface/Window.dox
+++ b/docs/user/interface/Window.dox
@@ -1046,11 +1046,12 @@
/*!
\fn void BWindow::MenusBeginning()
- \brief Hook method that gets called just before a menu owned by the
window is
- shown.
+ \brief Hook method that gets called just before an asynchronous pop-up
+ menu or a menu attached to a menu bar owned by the window is
+ opened.
\note This method is not invoked by a message, there is no
- \c B_MENUS_BEGINNING flag.
+ \c B_MENUS_BEGINNING or \c _MENUS_BEGUN_ command.
\since BeOS R3
*/
@@ -1058,11 +1059,12 @@
/*!
\fn void BWindow::MenusEnded()
- \brief Hook method that gets called just before a menu owned by the
window is
- hidden.
+ \brief Hook method that gets called just after an asynchronous pop-up
+ menu or a menu attached to a menu bar owned by the window is
+ closed.
- \note This method is not invoked by a message, there is no
- \c B_MENUS_ENDED flag.
+ You may invoke this method from another thread by sending a message
+ to the window with the \c _MENUS_DONE_ command (defined in AppDefs.h).
\since BeOS R3
*/
diff --git a/headers/os/interface/PopUpMenu.h b/headers/os/interface/PopUpMenu.h
index 2ecf6dd..36d82bd 100644
--- a/headers/os/interface/PopUpMenu.h
+++ b/headers/os/interface/PopUpMenu.h
@@ -74,6 +74,8 @@
static int32 _thread_entry(void* menuData);
+ static bool _HasMenuBar(BPopUpMenu*
popUpMenu);
+
private:
BPoint fWhere;
bool fUseWhere;
diff --git a/src/kits/interface/PopUpMenu.cpp b/src/kits/interface/PopUpMenu.cpp
index 7b94b38..c608b92 100644
--- a/src/kits/interface/PopUpMenu.cpp
+++ b/src/kits/interface/PopUpMenu.cpp
@@ -10,6 +10,7 @@
#include <Application.h>
#include <Looper.h>
+#include <MenuBar.h>
#include <MenuItem.h>
#include <PopUpMenu.h>
#include <Window.h>
@@ -347,14 +348,17 @@
// Get a pointer to the window from which Go() was called
BWindow* window
=
dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL)));
- data->window = window;
// Asynchronous menu: we set the BWindow menu's semaphore
// and let BWindow block when needed
- if (async && window != NULL)
+ if (async && window != NULL) {
+ if (!_HasMenuBar(this))
+ window->MenusBeginning();
_set_menu_sem_(window, sem);
+ }
data->object = this;
+ data->window = window;
data->autoInvoke = autoInvoke;
data->useRect = _specialRect != NULL;
if (_specialRect != NULL)
@@ -400,9 +404,13 @@
data->selected = menu->_StartTrack(data->where, data->autoInvoke,
data->startOpened, rect);
+ // We aren't the BWindow thread, so don't call MenusEnded() directly.
// Reset the window menu semaphore
- if (data->async && data->window)
+ if (data->async && data->window) {
+ if (!_HasMenuBar(data->object))
+ data->window->PostMessage(_MENUS_DONE_);
_set_menu_sem_(data->window, B_BAD_SEM_ID);
+ }
delete_sem(data->lock);
@@ -479,3 +487,29 @@
return selected;
}
+
+
+/* static */
+bool
+BPopUpMenu::_HasMenuBar(BPopUpMenu* popUpMenu)
+{
+ if (popUpMenu == NULL)
+ return false;
+
+ // we have a pop up menu;
+
+ BMenu* menu = static_cast<BMenu*>(popUpMenu);
+
+ // we have a menu, static_cast to an inherited class is guaranteed to
pass
+
+ BMenu* _menu;
+ while ((_menu = menu->Supermenu()) != NULL)
+ menu = _menu;
+
+ // went up the hierarchy and found the topmost menu ancestor
+ // (possibly ourself)
+
+ return dynamic_cast<BMenuBar*>(menu) != NULL;
+
+ // our topmost menu ancestor has been determined to be a BMenuBar or not
+}
--
To view, visit https://review.haiku-os.org/c/haiku/+/2289
To unsubscribe, or for help writing mail filters, visit
https://review.haiku-os.org/settings
Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: I0161272f968db419e4b2887ddebbef90810183c4
Gerrit-Change-Number: 2289
Gerrit-PatchSet: 1
Gerrit-Owner: John Scipione <jscipione@xxxxxxxxx>
Gerrit-MessageType: newchange