1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <rtl/math.hxx>
23 #include <tools/time.hxx>
25 #include <osx/saltimer.h>
26 #include <osx/salnstimer.h>
27 #include <osx/saldata.hxx>
28 #include <osx/salframe.h>
29 #include <osx/salinst.h>
32 void ImplNSAppPostEvent( short nEventId
, BOOL bAtStart
, int nUserData
)
34 ReleasePoolHolder aPool
;
35 NSEvent
* pEvent
= [NSEvent otherEventWithType
: NSEventTypeApplicationDefined
38 timestamp
: [[NSProcessInfo processInfo
] systemUptime
]
49 // nextEventMatchingMask has to run in the main thread!
50 assert([NSThread isMainThread
]);
52 // Posting an event to the end of an empty queue fails,
53 // so we peek the queue and post to the start, if empty.
54 // Some Qt bugs even indicate nextEvent without dequeue
55 // sometimes blocks, so we dequeue and re-add the event.
56 NSEvent
* pPeekEvent
= [NSApp nextEventMatchingMask
: NSEventMaskAny
58 inMode
: NSDefaultRunLoopMode
60 if ( nil
== pPeekEvent
)
63 [NSApp postEvent
: pPeekEvent atStart
: YES
];
65 [NSApp postEvent
: pEvent atStart
: bAtStart
];
68 void AquaSalTimer::queueDispatchTimerEvent( bool bAtStart
)
71 m_bDirectTimeout
= true;
72 ImplNSAppPostEvent( AquaSalInstance::DispatchTimerEvent
,
73 bAtStart
, GetNextEventVersion() );
76 void AquaSalTimer::Start( sal_uInt64 nMS
)
78 SalData
* pSalData
= GetSalData();
80 if( !pSalData
->mpInstance
->IsMainThread() )
82 ImplNSAppPostEvent( AquaSalInstance::AppStartTimerEvent
, YES
, nMS
);
86 m_bDirectTimeout
= (0 == nMS
) && !ImplGetSVData()->mpWinData
->mbIsLiveResize
;
87 if ( m_bDirectTimeout
)
91 NSTimeInterval aTI
= double(nMS
) / 1000.0;
92 if( m_pRunningTimer
!= nil
)
94 if ([m_pRunningTimer isValid
] && rtl::math::approxEqual(
95 [m_pRunningTimer timeInterval
], aTI
))
98 [m_pRunningTimer setFireDate
: [NSDate dateWithTimeIntervalSinceNow
: aTI
]];
105 if( m_pRunningTimer
== nil
)
107 m_pRunningTimer
= [[NSTimer scheduledTimerWithTimeInterval
: aTI
108 target
: [[[TimerCallbackCaller alloc
] init
] autorelease
]
109 selector
: @
selector(timerElapsed
:)
113 /* #i84055# add timer to tracking run loop mode,
114 so they also elapse while e.g. life resize
116 [[NSRunLoop currentRunLoop
] addTimer
: m_pRunningTimer forMode
: NSEventTrackingRunLoopMode
];
121 void AquaSalTimer::Stop()
123 assert( GetSalData()->mpInstance
->IsMainThread() );
125 if( m_pRunningTimer
!= nil
)
127 [m_pRunningTimer invalidate
];
128 [m_pRunningTimer release
];
129 m_pRunningTimer
= nil
;
134 void AquaSalTimer::callTimerCallback()
136 ImplSVData
* pSVData
= ImplGetSVData();
137 SolarMutexGuard aGuard
;
138 m_bDirectTimeout
= false;
139 if( pSVData
->maSchedCtx
.mpSalTimer
)
140 pSVData
->maSchedCtx
.mpSalTimer
->CallCallback();
143 void AquaSalTimer::handleTimerElapsed()
145 if ( m_bDirectTimeout
|| ImplGetSVData()->mpWinData
->mbIsLiveResize
)
147 // Stop the timer, as it is just invalidated after the firing function
152 queueDispatchTimerEvent( true );
155 bool AquaSalTimer::handleDispatchTimerEvent( NSEvent
*pEvent
)
157 bool bIsValidEvent
= IsValidEventVersion( [pEvent data1
] );
160 return bIsValidEvent
;
163 void AquaSalTimer::handleStartTimerEvent( NSEvent
* pEvent
)
165 ImplSVData
* pSVData
= ImplGetSVData();
166 if( pSVData
->maSchedCtx
.mpSalTimer
)
168 NSTimeInterval posted
= [pEvent timestamp
] + NSTimeInterval([pEvent data1
])/1000.0;
169 NSTimeInterval current
= [NSDate timeIntervalSinceReferenceDate
];
170 sal_uLong nTimeoutMS
= 0;
171 if( (posted
- current
) > 0.0 )
172 nTimeoutMS
= ceil( (posted
- current
) * 1000 );
177 bool AquaSalTimer::IsTimerElapsed() const
179 assert( !((ExistsValidEvent() || m_bDirectTimeout
) && m_pRunningTimer
) );
180 if ( ExistsValidEvent() || m_bDirectTimeout
)
182 if ( !m_pRunningTimer
)
184 NSDate
* pDt
= [m_pRunningTimer fireDate
];
185 return pDt
&& ([pDt timeIntervalSinceNow
] < 0);
188 AquaSalTimer::AquaSalTimer( )
189 : m_pRunningTimer( nil
)
193 AquaSalTimer::~AquaSalTimer()
198 void AquaSalTimer::handleWindowShouldClose()
200 // for whatever reason events get filtered on close, presumably by
201 // timestamp so post a new timeout event, if there was one queued...
202 if ( ExistsValidEvent() && !m_pRunningTimer
)
203 queueDispatchTimerEvent( false );
206 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */