Browse Source

Create a new run loop observer for a nested loop if it's being started from an observer callback (#15425)

Co-authored-by: Nikita Tsukanov <kekekeks@Nikitas-MacBook-Pro.local>
pull/15440/head
Nikita Tsukanov 2 years ago
committed by GitHub
parent
commit
27e40b820e
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 91
      native/Avalonia.Native/src/OSX/platformthreading.mm

91
native/Avalonia.Native/src/OSX/platformthreading.mm

@ -52,6 +52,39 @@ public:
// interval—on the order of decades or more" // interval—on the order of decades or more"
static double distantFutureInterval = (double)50*365*24*3600; static double distantFutureInterval = (double)50*365*24*3600;
@implementation ObserverStateHolder : NSObject
{
@public bool InsideCallback;
}
@end
@implementation ObserverHolder : NSObject
{
@public CFRunLoopObserverRef Observer;
@public ObserverStateHolder* State;
}
- (ObserverHolder*) init
{
self = [super init];
self->State = [ObserverStateHolder new];
return self;
}
- (void) dealloc
{
if(Observer != nil)
{
CFRunLoopObserverInvalidate(Observer);
CFRelease(Observer);
Observer = nil;
}
}
@end
@interface Signaler : NSObject @interface Signaler : NSObject
-(void) setEvents:(IAvnPlatformThreadingInterfaceEvents*) events; -(void) setEvents:(IAvnPlatformThreadingInterfaceEvents*) events;
-(void) updateTimer:(int)ms; -(void) updateTimer:(int)ms;
@ -66,7 +99,7 @@ static double distantFutureInterval = (double)50*365*24*3600;
bool _wakeupDelegateSent; bool _wakeupDelegateSent;
bool _signaled; bool _signaled;
bool _backgroundProcessingRequested; bool _backgroundProcessingRequested;
CFRunLoopObserverRef _observer; @public ObserverHolder* Observer;
CFRunLoopTimerRef _timer; CFRunLoopTimerRef _timer;
} }
@ -83,15 +116,19 @@ static double distantFutureInterval = (double)50*365*24*3600;
} }
} }
- (Signaler*) init - (ObserverHolder*) createObserver
{ {
_observer = CFRunLoopObserverCreateWithHandler(nil, ObserverHolder* holder = [ObserverHolder new];
ObserverStateHolder* state = holder->State;
holder->Observer = CFRunLoopObserverCreateWithHandler(nil,
kCFRunLoopBeforeSources kCFRunLoopBeforeSources
| kCFRunLoopAfterWaiting | kCFRunLoopAfterWaiting
| kCFRunLoopBeforeWaiting | kCFRunLoopBeforeWaiting
, ,
true, 0, true, 0,
^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
state->InsideCallback = true;
if(activity == kCFRunLoopBeforeWaiting) if(activity == kCFRunLoopBeforeWaiting)
{ {
bool triggerProcessing; bool triggerProcessing;
@ -103,10 +140,15 @@ static double distantFutureInterval = (double)50*365*24*3600;
self->_events->ReadyForBackgroundProcessing(); self->_events->ReadyForBackgroundProcessing();
} }
[self checkSignaled]; [self checkSignaled];
state->InsideCallback = false;
}); });
CFRunLoopAddObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes); CFRunLoopAddObserver(CFRunLoopGetMain(), holder->Observer, kCFRunLoopCommonModes);
return holder;
}
- (Signaler*) init
{
Observer = [self createObserver];
_timer = CFRunLoopTimerCreateWithHandler(nil, CFAbsoluteTimeGetCurrent() + distantFutureInterval, distantFutureInterval, 0, 0, ^(CFRunLoopTimerRef timer) { _timer = CFRunLoopTimerCreateWithHandler(nil, CFAbsoluteTimeGetCurrent() + distantFutureInterval, distantFutureInterval, 0, 0, ^(CFRunLoopTimerRef timer) {
self->_events->Timer(); self->_events->Timer();
}); });
@ -118,12 +160,7 @@ static double distantFutureInterval = (double)50*365*24*3600;
- (void) destroyObserver - (void) destroyObserver
{ {
if(_observer != nil) Observer = nil;
{
CFRunLoopObserverInvalidate(_observer);
CFRelease(_observer);
_observer = nil;
}
if(_timer != nil) if(_timer != nil)
{ {
@ -182,12 +219,13 @@ class PlatformThreadingInterface : public ComSingleObject<IAvnPlatformThreadingI
private: private:
ComPtr<IAvnPlatformThreadingInterfaceEvents> _events; ComPtr<IAvnPlatformThreadingInterfaceEvents> _events;
Signaler* _signaler; Signaler* _signaler;
CFRunLoopObserverRef _observer = nil; ObserverHolder* _currentObserver;
public: public:
FORWARD_IUNKNOWN() FORWARD_IUNKNOWN()
PlatformThreadingInterface() PlatformThreadingInterface()
{ {
_signaler = [Signaler new]; _signaler = [Signaler new];
_currentObserver = _signaler->Observer;
}; };
~PlatformThreadingInterface() ~PlatformThreadingInterface()
@ -228,18 +266,25 @@ public:
} }
else else
{ {
while(!can->Cancelled) @autoreleasepool {
{ auto previousObserver = _currentObserver;
@autoreleasepool if(_currentObserver->State->InsideCallback)
_currentObserver = [_signaler createObserver];
while(!can->Cancelled)
{ {
NSEvent* ev = [NSApp @autoreleasepool
nextEventMatchingMask:NSEventMaskAny {
untilDate: [NSDate dateWithTimeIntervalSinceNow:1] NSEvent* ev = [NSApp
inMode:NSDefaultRunLoopMode nextEventMatchingMask:NSEventMaskAny
dequeue:true]; untilDate: [NSDate dateWithTimeIntervalSinceNow:1]
if(ev != NULL) inMode:NSDefaultRunLoopMode
[NSApp sendEvent:ev]; dequeue:true];
if(ev != NULL)
[NSApp sendEvent:ev];
}
} }
_currentObserver = previousObserver;
} }
} }
}; };

Loading…
Cancel
Save