summaryrefslogtreecommitdiff
path: root/vcl/osx
diff options
context:
space:
mode:
authorJan-Marek Glogowski <glogow@fbihome.de>2017-03-21 13:32:47 +0100
committerJan-Marek Glogowski <glogow@fbihome.de>2017-07-13 12:10:27 +0200
commit272026d70129603e1824b802a2a6920adcd09dc0 (patch)
treebcc3db683252eee20a977f961adcbecce351f180 /vcl/osx
parentf0aabfe601223cee214b0be1b2ebf51a80b68f2c (diff)
OSX fix empty message queue handling
For some (unknown) reason [NSApp postEvent: ... atStart: NO] doesn't append the event, if the message queue is empty (AKA [NSApp nextEventMatchingMask .. ] returns nil). Due to nextEventMatchingMask usage, these postEvents have to run in the main thread. Using performSelectorOnMainThread deadlocks, since the calling thread may have locked the Yield mutex, so we simply defer the call using an NSEvent, like the Windows backend. So we have to peek at the queue and if it's empty simply prepend the event using [.. atStart: YES]. In the end this make the vcl_timer unit test pass on OSX. Change-Id: Ib41186425b2f76faa0e9f116f47fdcd60d878099
Diffstat (limited to 'vcl/osx')
-rw-r--r--vcl/osx/salinst.cxx38
-rw-r--r--vcl/osx/salnstimer.mm17
-rw-r--r--vcl/osx/saltimer.cxx45
3 files changed, 47 insertions, 53 deletions
diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx
index 5936c0618805..bff9c3816d22 100644
--- a/vcl/osx/salinst.cxx
+++ b/vcl/osx/salinst.cxx
@@ -368,23 +368,7 @@ void AquaSalInstance::wakeupYield()
{
// wakeup :Yield
if( mbWaitingYield )
- {
- SalData::ensureThreadAutoreleasePool();
-SAL_WNODEPRECATED_DECLARATIONS_PUSH
- // 'NSApplicationDefined' is deprecated: first deprecated in macOS 10.12
- NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined
- location: NSZeroPoint
- modifierFlags: 0
- timestamp: 0
- windowNumber: 0
- context: nil
- subtype: AquaSalInstance::YieldWakeupEvent
- data1: 0
- data2: 0 ];
-SAL_WNODEPRECATED_DECLARATIONS_POP
- if( pEvent )
- [NSApp postEvent: pEvent atStart: NO];
- }
+ ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, YES );
}
void AquaSalInstance::PostUserEvent( AquaSalFrame* pFrame, SalEvent nType, void* pData )
@@ -554,14 +538,6 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent )
};
}
-class ReleasePoolHolder
-{
- NSAutoreleasePool* mpPool;
- public:
- ReleasePoolHolder() : mpPool( [[NSAutoreleasePool alloc] init] ) {}
- ~ReleasePoolHolder() { [mpPool release]; }
-};
-
bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
{
(void) nReleased;
@@ -627,9 +603,11 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLon
SAL_WNODEPRECATED_DECLARATIONS_PUSH
// 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12
- pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: nil
+ pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask
SAL_WNODEPRECATED_DECLARATIONS_POP
- inMode: NSDefaultRunLoopMode dequeue: YES];
+ untilDate: nil
+ inMode: NSDefaultRunLoopMode
+ dequeue: YES];
if( pEvent )
{
[NSApp sendEvent: pEvent];
@@ -648,9 +626,11 @@ SAL_WNODEPRECATED_DECLARATIONS_POP
NSDate* pDt = AquaSalTimer::pRunningTimer ? [AquaSalTimer::pRunningTimer fireDate] : [NSDate distantFuture];
SAL_WNODEPRECATED_DECLARATIONS_PUSH
// 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12
- pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: pDt
+ pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask
SAL_WNODEPRECATED_DECLARATIONS_POP
- inMode: NSDefaultRunLoopMode dequeue: YES];
+ untilDate: pDt
+ inMode: NSDefaultRunLoopMode
+ dequeue: YES];
if( pEvent )
[NSApp sendEvent: pEvent];
[NSApp updateWindows];
diff --git a/vcl/osx/salnstimer.mm b/vcl/osx/salnstimer.mm
index 9c3264295d60..c9867cf7a79e 100644
--- a/vcl/osx/salnstimer.mm
+++ b/vcl/osx/salnstimer.mm
@@ -26,24 +26,13 @@
#include "svdata.hxx"
@implementation TimerCallbackCaller
+
-(void)timerElapsed:(NSTimer*)pTimer
{
(void)pTimer;
-SAL_WNODEPRECATED_DECLARATIONS_PUSH
-// 'NSApplicationDefined' is deprecated: first deprecated in macOS 10.12
- NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined
-SAL_WNODEPRECATED_DECLARATIONS_POP
- location: NSZeroPoint
- modifierFlags: 0
- timestamp: [NSDate timeIntervalSinceReferenceDate]
- windowNumber: 0
- context: nil
- subtype: AquaSalInstance::DispatchTimerEvent
- data1: 0
- data2: 0 ];
- assert( pEvent );
- [NSApp postEvent: pEvent atStart: YES];
+ ImplNSAppPostEvent( AquaSalInstance::DispatchTimerEvent, YES );
}
+
@end
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/osx/saltimer.cxx b/vcl/osx/saltimer.cxx
index 415ad1284af8..3cf74529a301 100644
--- a/vcl/osx/saltimer.cxx
+++ b/vcl/osx/saltimer.cxx
@@ -31,22 +31,45 @@ NSTimer* AquaSalTimer::pRunningTimer = nil;
static void ImplSalStopTimer();
-static inline void ImplPostEvent( short nEventId, bool bAtStart, int nUserData = 0 )
+void ImplNSAppPostEvent( short nEventId, BOOL bAtStart, int nUserData )
{
- SalData::ensureThreadAutoreleasePool();
+ ReleasePoolHolder aPool;
SAL_WNODEPRECATED_DECLARATIONS_PUSH
// 'NSApplicationDefined' is deprecated: first deprecated in macOS 10.12
NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined
SAL_WNODEPRECATED_DECLARATIONS_POP
location: NSZeroPoint
modifierFlags: 0
- timestamp: [NSDate timeIntervalSinceReferenceDate]
+ timestamp: 0
windowNumber: 0
context: nil
subtype: nEventId
data1: nUserData
- data2: 0 ];
+ data2: 0];
assert( pEvent );
+ if ( nil == pEvent )
+ return;
+ if ( NO == bAtStart )
+ {
+ // nextEventMatchingMask has to run in the main thread!
+ assert([NSThread isMainThread]);
+
+ // Posting an event to the end of an empty queue fails,
+ // so we peek the queue and post to the start, if empty.
+ // Some Qt bugs even indicate nextEvent without dequeue
+ // sometimes blocks, so we dequeue and re-add the event.
+SAL_WNODEPRECATED_DECLARATIONS_PUSH
+// 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12
+ NSEvent* pPeekEvent = [NSApp nextEventMatchingMask: NSAnyEventMask
+SAL_WNODEPRECATED_DECLARATIONS_POP
+ untilDate: nil
+ inMode: NSDefaultRunLoopMode
+ dequeue: YES];
+ if ( nil == pPeekEvent )
+ bAtStart = YES;
+ else
+ [NSApp postEvent: pPeekEvent atStart: YES];
+ }
[NSApp postEvent: pEvent atStart: bAtStart];
}
@@ -54,14 +77,18 @@ static void ImplSalStartTimer( sal_uLong nMS )
{
SalData* pSalData = GetSalData();
- if ( 0 == nMS )
+ if( !pSalData->mpFirstInstance->IsMainThread() )
{
- ImplSalStopTimer();
- ImplPostEvent( AquaSalInstance::DispatchTimerEvent, false );
+ ImplNSAppPostEvent( AquaSalInstance::AppStartTimerEvent, YES, nMS );
return;
}
- if( pSalData->mpFirstInstance->IsMainThread() )
+ if ( 0 == nMS )
+ {
+ ImplSalStopTimer();
+ ImplNSAppPostEvent( AquaSalInstance::DispatchTimerEvent, NO );
+ }
+ else
{
NSTimeInterval aTI = double(nMS) / 1000.0;
if( AquaSalTimer::pRunningTimer != nil )
@@ -89,8 +116,6 @@ static void ImplSalStartTimer( sal_uLong nMS )
[[NSRunLoop currentRunLoop] addTimer: AquaSalTimer::pRunningTimer forMode: NSEventTrackingRunLoopMode];
}
}
- else
- ImplPostEvent( AquaSalInstance::AppStartTimerEvent, true, nMS );
}
static void ImplSalStopTimer()