From b6cb1927f39786de37d829a8677fe9cac2693a94 Mon Sep 17 00:00:00 2001 From: Guille Polito Date: Wed, 31 Oct 2018 10:46:37 +0100 Subject: [PATCH] Consume all events in the event queue to avoid application lockups --- .../vm/OSX/sqSqueakOSXApplication+events.m | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/platforms/iOS/vm/OSX/sqSqueakOSXApplication+events.m b/platforms/iOS/vm/OSX/sqSqueakOSXApplication+events.m index d61fff7c5a..b7ccfff7c5 100644 --- a/platforms/iOS/vm/OSX/sqSqueakOSXApplication+events.m +++ b/platforms/iOS/vm/OSX/sqSqueakOSXApplication+events.m @@ -67,27 +67,37 @@ - (sqButton) resolveModifier:(sqModifier)modifier forMouseButton:(sqButton)mouse @implementation sqSqueakOSXApplication (events) +// Consume all pending events in the NSApp +// Events may come from the window open by the VM or windows open by other windowing systems +// We need to consume all events in the queue, otherwise this may produce lockups when e.g., switching resolutions +// If the event does not correspond to this window, we take it from the event queue anyways and re-post it afterwards +// This gives other windows the opportunity to consume their events - (void) pumpRunLoopEventSendAndSignal:(BOOL)signal { - NSEvent *event; - while (event = [NSApp nextEventMatchingMask:NSEventMaskAny - untilDate:nil - inMode:NSEventTrackingRunLoopMode - dequeue:NO]) { - // If the event is not a system event or an event of *this* window, stop consuming events - // In case of multi window applications, it is the responsibility of the other windowing systems to consume their own events - // This is a cooperative event handling mechanism for simplicity - // Single window systems will be not affected by it - if (!(event.window == 0 || event.window == gDelegateApp.window)){ - break; - } - [NSApp sendEvent: [NSApp nextEventMatchingMask:NSEventMaskAny - untilDate:nil - inMode:NSEventTrackingRunLoopMode - dequeue:YES]]; - if (signal) { - interpreterProxy->signalSemaphoreWithIndex(gDelegateApp.squeakApplication.inputSemaphoreIndex); - } - } + NSEvent *event; + NSMutableArray *alienEventQueue = [[NSMutableArray alloc] init]; + while (event = [NSApp nextEventMatchingMask:NSEventMaskAny + untilDate:nil + inMode:NSEventTrackingRunLoopMode + dequeue:YES]) { + // If the event is not a system event or an event of *this* window, queue the event + // Otherwise treat the event normally and send it to the app + if (event.window && event.window != gDelegateApp.window){ + [alienEventQueue addObject: event]; + }else{ + [NSApp sendEvent: event]; + if (signal) { + interpreterProxy->signalSemaphoreWithIndex(gDelegateApp.squeakApplication.inputSemaphoreIndex); + } + } + } + + // Put back in the queue all events that did not belong to this window + // They will be managed by other windowing systems + // (or by a subsequent invocation to this function) + while (event = [alienEventQueue firstObject]){ + [NSApp postEvent: event atStart: NO]; + [alienEventQueue removeObject: event]; + } } - (void) pumpRunLoop {