mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1707598 - Add -[MOZMenuOpeningCoordinator runAfterMenuClosed:]. r=harry
This is a robust way to queue runnables which won't run until after the nested event loop of the open NSMenu has been exited. NS_DispatchToCurrentThread is not a reliable way to achieve that, because it puts the runnables into the Gecko event loop, and there's nothing that prevents us from potentially visiting the Gecko event loop inside the NSMenu's event loop, even after cancelTracking(WithoutAnimation) has been called. Differential Revision: https://phabricator.services.mozilla.com/D113733
This commit is contained in:
parent
83880d0070
commit
85bc33f0da
@ -8,6 +8,12 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#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<mozilla::Runnable>&&)aRunnable;
|
||||
|
||||
@end
|
||||
|
||||
#endif // MOZMenuOpeningCoordinator_h
|
||||
|
@ -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<mozilla::Runnable> 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<mozilla::Runnable>&&)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.
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user