diff --git a/widget/cocoa/MOZMenuOpeningCoordinator.h b/widget/cocoa/MOZMenuOpeningCoordinator.h index 3e4dfe61f09d..43a366f24b52 100644 --- a/widget/cocoa/MOZMenuOpeningCoordinator.h +++ b/widget/cocoa/MOZMenuOpeningCoordinator.h @@ -8,6 +8,12 @@ #import +#include "mozilla/RefPtr.h" + +namespace mozilla { +class Runnable; +} + /* * MOZMenuOpeningCoordinator is a workaround for the fact that opening an NSMenu creates a nested * event loop. This event loop is only exited after the menu is closed. The caller of @@ -32,6 +38,10 @@ // Can only be called on the main thread. - (void)cancelAsynchronousOpening:(NSInteger)aHandle; +// Run aRunnable once the nested event loop of the currently open menu has been exited. +// If no menu is currently open, post the runnable with NS_DispatchToCurrentThread. +- (void)runAfterMenuClosed:(RefPtr&&)aRunnable; + @end #endif // MOZMenuOpeningCoordinator_h diff --git a/widget/cocoa/MOZMenuOpeningCoordinator.mm b/widget/cocoa/MOZMenuOpeningCoordinator.mm index a482aa5a9e30..8b60431e17f9 100644 --- a/widget/cocoa/MOZMenuOpeningCoordinator.mm +++ b/widget/cocoa/MOZMenuOpeningCoordinator.mm @@ -14,7 +14,9 @@ #include "nsCocoaFeatures.h" #include "nsCocoaUtils.h" +#include "nsDeque.h" #include "nsObjCExceptions.h" +#include "nsThreadUtils.h" #include "SDKDeclarations.h" @interface MOZMenuOpeningInfo : NSObject @@ -32,6 +34,10 @@ // time at at which it is unqueued in _runMenu. MOZMenuOpeningInfo* mPendingOpening; // strong + // Any runnables we want to run after the current menu event loop has been exited. + // Only non-empty if mRunMenuIsOnTheStack is true. + nsRefPtrDeque mPendingAfterMenuCloseRunnables; + // An incrementing counter NSInteger mLastHandle; @@ -99,6 +105,12 @@ } [info release]; + + // We have exited _openMenu's nested event loop. Dispatch any pending "after menu close" + // runnables to the event loop. + while (mPendingAfterMenuCloseRunnables.GetSize() != 0) { + NS_DispatchToCurrentThread(mPendingAfterMenuCloseRunnables.PopFront()); + } } mRunMenuIsOnTheStack = NO; @@ -111,6 +123,16 @@ } } +- (void)runAfterMenuClosed:(RefPtr&&)aRunnable { + MOZ_RELEASE_ASSERT(aRunnable); + + if (mRunMenuIsOnTheStack) { + mPendingAfterMenuCloseRunnables.Push(aRunnable.forget()); + } else { + NS_DispatchToCurrentThread(aRunnable.forget()); + } +} + - (void)_openMenu:(NSMenu*)aMenu atScreenPosition:(NSPoint)aPosition forView:(NSView*)aView { // There are multiple ways to display an NSMenu as a context menu. //