1/**************************************************************************** 2** 3** Copyright (C) 2018 The Qt Company Ltd. 4** Contact: https://www.qt.io/licensing/ 5** 6** This file is part of the QtBluetooth module of the Qt Toolkit. 7** 8** $QT_BEGIN_LICENSE:LGPL$ 9** Commercial License Usage 10** Licensees holding valid commercial Qt licenses may use this file in 11** accordance with the commercial license agreement provided with the 12** Software or, alternatively, in accordance with the terms contained in 13** a written agreement between you and The Qt Company. For licensing terms 14** and conditions see https://www.qt.io/terms-conditions. For further 15** information use the contact form at https://www.qt.io/contact-us. 16** 17** GNU Lesser General Public License Usage 18** Alternatively, this file may be used under the terms of the GNU Lesser 19** General Public License version 3 as published by the Free Software 20** Foundation and appearing in the file LICENSE.LGPL3 included in the 21** packaging of this file. Please review the following information to 22** ensure the GNU Lesser General Public License version 3 requirements 23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24** 25** GNU General Public License Usage 26** Alternatively, this file may be used under the terms of the GNU 27** General Public License version 2.0 or (at your option) the GNU General 28** Public license version 3 or any later version approved by the KDE Free 29** Qt Foundation. The licenses are as published by the Free Software 30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31** included in the packaging of this file. Please review the following 32** information to ensure the GNU General Public License requirements will 33** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34** https://www.gnu.org/licenses/gpl-3.0.html. 35** 36** $QT_END_LICENSE$ 37** 38****************************************************************************/ 39 40#include "osxbtgcdtimer_p.h" 41#include "osxbtutility_p.h" 42 43#include <QtCore/qdebug.h> 44 45#include <algorithm> 46 47QT_USE_NAMESPACE 48using namespace OSXBluetooth; 49 50@implementation QT_MANGLE_NAMESPACE(OSXBTGCDTimer) { 51@private 52 qint64 timeoutMS; 53 qint64 timeoutStepMS; 54 55 // Optional: 56 id objectUnderWatch; 57 OperationTimeout timeoutType; 58 59 QElapsedTimer timer; 60 id<QT_MANGLE_NAMESPACE(GCDTimerDelegate)> timeoutHandler; 61 62 bool cancelled; 63} 64 65- (instancetype)initWithDelegate:(id<QT_MANGLE_NAMESPACE(GCDTimerDelegate)>)delegate 66{ 67 if (self = [super init]) { 68 timeoutHandler = delegate; 69 timeoutMS = 0; 70 timeoutStepMS = 0; 71 objectUnderWatch = nil; 72 timeoutType = OperationTimeout::none; 73 cancelled = false; 74 } 75 return self; 76} 77 78- (void)watchAfter:(id)object withTimeoutType:(OperationTimeout)type 79{ 80 objectUnderWatch = object; 81 timeoutType = type; 82} 83 84- (void)startWithTimeout:(qint64)ms step:(qint64)stepMS 85{ 86 Q_ASSERT(!timeoutMS && !timeoutStepMS); 87 Q_ASSERT(!cancelled); 88 89 if (!timeoutHandler) { 90 // Nobody to report timeout to, no need to start any task then. 91 return; 92 } 93 94 if (ms <= 0 || stepMS <= 0) { 95 qCWarning(QT_BT_OSX, "Invalid timeout/step parameters"); 96 return; 97 } 98 99 timeoutMS = ms; 100 timeoutStepMS = stepMS; 101 timer.start(); 102 103 [self handleTimeout]; 104} 105 106- (void)handleTimeout 107{ 108 if (cancelled) 109 return; 110 111 const qint64 elapsed = timer.elapsed(); 112 if (elapsed >= timeoutMS) { 113 [timeoutHandler timeout:self]; 114 } else { 115 // Re-schedule: 116 dispatch_queue_t leQueue(qt_LE_queue()); 117 Q_ASSERT(leQueue); 118 const qint64 timeChunkMS = std::min(timeoutMS - elapsed, timeoutStepMS); 119 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 120 int64_t(timeChunkMS / 1000. * NSEC_PER_SEC)), 121 leQueue, 122 ^{ 123 [self handleTimeout]; 124 }); 125 } 126} 127 128- (void)cancelTimer 129{ 130 cancelled = true; 131 timeoutHandler = nil; 132 objectUnderWatch = nil; 133 timeoutType = OperationTimeout::none; 134} 135 136- (id)objectUnderWatch 137{ 138 return objectUnderWatch; 139} 140 141- (OperationTimeout)timeoutType 142{ 143 return timeoutType; 144} 145 146@end 147