[prev in list] [next in list] [prev in thread] [next in thread] 

List:       haiku-commits
Subject:    [haiku-commits] Change in haiku[master]: BPopUpMenu: Call MenusBeginning() and MenusEnded() hook met
From:       Gerrit <review () review ! haiku-os ! org>
Date:       2020-02-27 23:25:00
Message-ID: gerrit.1582845898000.I0161272f968db419e4b2887ddebbef90810183c4 () review ! haiku-os ! org
[Download RAW message or body]

From John Scipione <jscipione@gmail.com>:

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@gmail.com>
Gerrit-MessageType: newchange

[Attachment #3 (text/html)]

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

<div style="display:none"> Gerrit-Project: haiku </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: \
I0161272f968db419e4b2887ddebbef90810183c4 </div> <div style="display:none"> \
Gerrit-Change-Number: 2289 </div> <div style="display:none"> Gerrit-PatchSet: 1 \
</div> <div style="display:none"> Gerrit-Owner: John Scipione \
&lt;jscipione@gmail.com&gt; </div> <div style="display:none"> Gerrit-MessageType: \
newchange </div>



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic