File indexing completed on 2025-02-16 03:41:31
0001 /* This file is part of the KDE libraries 0002 * SPDX-FileCopyrightText: 2009 Dario Freddi <drf at kde.org> 0003 * SPDX-FileCopyrightText: 2003 Tarkvara Design Inc. (from KVIrc source code) 0004 * SPDX-FileCopyrightText: 2008 Roman Jarosz <kedgedev at centrum.cz> 0005 * SPDX-FileCopyrightText: 2008 the Kopete developers <kopete-devel at kde.org> 0006 * 0007 * SPDX-License-Identifier: LGPL-2.1-or-later 0008 */ 0009 0010 #include "macpoller.h" 0011 0012 // Why does Apple have to make this so complicated? 0013 static OSStatus LoadFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr) 0014 { 0015 OSStatus err; 0016 FSRef frameworksFolderRef; 0017 CFURLRef baseURL; 0018 CFURLRef bundleURL; 0019 0020 if (bundlePtr == nil) { 0021 return (-1); 0022 } 0023 0024 *bundlePtr = nil; 0025 0026 baseURL = nil; 0027 bundleURL = nil; 0028 0029 err = FSFindFolder(kOnAppropriateDisk, kFrameworksFolderType, true, &frameworksFolderRef); 0030 if (err == noErr) { 0031 baseURL = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &frameworksFolderRef); 0032 if (baseURL == nil) { 0033 err = coreFoundationUnknownErr; 0034 } 0035 } 0036 0037 if (err == noErr) { 0038 bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, framework, false); 0039 if (bundleURL == nil) { 0040 err = coreFoundationUnknownErr; 0041 } 0042 } 0043 0044 if (err == noErr) { 0045 *bundlePtr = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL); 0046 if (*bundlePtr == nil) { 0047 err = coreFoundationUnknownErr; 0048 } 0049 } 0050 0051 if (err == noErr) { 0052 if (!CFBundleLoadExecutable(*bundlePtr)) { 0053 err = coreFoundationUnknownErr; 0054 } 0055 } 0056 0057 // Clean up. 0058 if (err != noErr && *bundlePtr != nil) { 0059 CFRelease(*bundlePtr); 0060 *bundlePtr = nil; 0061 } 0062 0063 if (bundleURL != nil) { 0064 CFRelease(bundleURL); 0065 } 0066 0067 if (baseURL != nil) { 0068 CFRelease(baseURL); 0069 } 0070 0071 return err; 0072 } 0073 0074 pascal void MacPoller::IdleTimerAction(EventLoopTimerRef, EventLoopIdleTimerMessage inState, void *inUserData) 0075 { 0076 Q_ASSERT(inUserData); 0077 switch (inState) { 0078 case kEventLoopIdleTimerStarted: 0079 case kEventLoopIdleTimerStopped: 0080 // Get invoked with this constant at the start of the idle period, 0081 // or whenever user activity cancels the idle. 0082 ((MacPoller *)inUserData)->m_secondsIdle = 0; 0083 ((MacPoller *)inUserData)->triggerResume(); 0084 break; 0085 case kEventLoopIdleTimerIdling: 0086 // Called every time the timer fires (i.e. every second). 0087 ((MacPoller *)inUserData)->m_secondsIdle++; 0088 ((MacPoller *)inUserData)->poll(); 0089 break; 0090 } 0091 } 0092 0093 // Typedef for the function we're getting back from CFBundleGetFunctionPointerForName. 0094 typedef OSStatus (*InstallEventLoopIdleTimerPtr)(EventLoopRef inEventLoop, 0095 EventTimerInterval inFireDelay, 0096 EventTimerInterval inInterval, 0097 EventLoopIdleTimerUPP inTimerProc, 0098 void *inTimerData, 0099 EventLoopTimerRef *outTimer); 0100 0101 MacPoller::MacPoller(QObject *parent) 0102 : KAbstractIdleTimePoller(parent) 0103 , m_timerRef(0) 0104 , m_secondsIdle(0) 0105 , m_catch(false) 0106 { 0107 } 0108 0109 MacPoller::~MacPoller() 0110 { 0111 } 0112 0113 void MacPoller::unloadPoller() 0114 { 0115 RemoveEventLoopTimer(m_timerRef); 0116 } 0117 0118 bool MacPoller::isAvailable() 0119 { 0120 return true; 0121 } 0122 0123 bool MacPoller::setUpPoller() 0124 { 0125 // May already be init'ed. 0126 if (m_timerRef) { 0127 return true; 0128 } 0129 0130 // According to the docs, InstallEventLoopIdleTimer is new in 10.2. 0131 // According to the headers, it has been around since 10.0. 0132 // One of them is lying. We'll play it safe and weak-link the function. 0133 0134 // Load the "Carbon.framework" bundle. 0135 CFBundleRef carbonBundle; 0136 0137 if (LoadFrameworkBundle(CFSTR("Carbon.framework"), &carbonBundle) != noErr) { 0138 return false; 0139 } 0140 0141 // Load the Mach-O function pointers for the routine we will be using. 0142 InstallEventLoopIdleTimerPtr myInstallEventLoopIdleTimer = 0143 (InstallEventLoopIdleTimerPtr)CFBundleGetFunctionPointerForName(carbonBundle, CFSTR("InstallEventLoopIdleTimer")); 0144 0145 if (myInstallEventLoopIdleTimer == 0) { 0146 return false; 0147 } 0148 0149 EventLoopIdleTimerUPP timerUPP = NewEventLoopIdleTimerUPP(IdleTimerAction); 0150 if ((*myInstallEventLoopIdleTimer)(GetMainEventLoop(), kEventDurationSecond, kEventDurationSecond, timerUPP, this, &m_timerRef)) { 0151 return true; 0152 } 0153 0154 return false; 0155 } 0156 0157 QList<int> MacPoller::timeouts() const 0158 { 0159 return m_timeouts; 0160 } 0161 0162 void MacPoller::addTimeout(int nextTimeout) 0163 { 0164 m_timeouts.append(nextTimeout); 0165 poll(); 0166 } 0167 0168 int MacPoller::poll() 0169 { 0170 int idle = m_secondsIdle * 1000; 0171 0172 // Check if we reached a timeout.. 0173 for (int i : std::as_const(m_timeouts)) { 0174 if ((i - idle < 1000 && i > idle) || (idle - i < 1000 && idle > i)) { 0175 // Bingo! 0176 Q_EMIT timeoutReached(i); 0177 } 0178 } 0179 0180 return idle; 0181 } 0182 0183 int MacPoller::forcePollRequest() 0184 { 0185 return poll(); 0186 } 0187 0188 void MacPoller::removeTimeout(int timeout) 0189 { 0190 m_timeouts.removeOne(timeout); 0191 poll(); 0192 } 0193 0194 void MacPoller::catchIdleEvent() 0195 { 0196 m_catch = true; 0197 } 0198 0199 void MacPoller::stopCatchingIdleEvents() 0200 { 0201 m_catch = false; 0202 } 0203 0204 void MacPoller::triggerResume() 0205 { 0206 if (m_catch) { 0207 Q_EMIT resumingFromIdle(); 0208 stopCatchingIdleEvents(); 0209 } 0210 } 0211 0212 void MacPoller::simulateUserActivity() 0213 { 0214 // TODO 0215 } 0216 0217 #include "moc_macpoller.cpp"