KIdleTime

macpoller.cpp
1/* This file is part of the KDE libraries
2 * SPDX-FileCopyrightText: 2009 Dario Freddi <drf at kde.org>
3 * SPDX-FileCopyrightText: 2003 Tarkvara Design Inc. (from KVIrc source code)
4 * SPDX-FileCopyrightText: 2008 Roman Jarosz <kedgedev at centrum.cz>
5 * SPDX-FileCopyrightText: 2008 the Kopete developers <kopete-devel at kde.org>
6 *
7 * SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9
10#include "macpoller.h"
11
12// Why does Apple have to make this so complicated?
13static OSStatus LoadFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr)
14{
15 OSStatus err;
16 FSRef frameworksFolderRef;
17 CFURLRef baseURL;
18 CFURLRef bundleURL;
19
20 if (bundlePtr == nil) {
21 return (-1);
22 }
23
24 *bundlePtr = nil;
25
26 baseURL = nil;
27 bundleURL = nil;
28
29 err = FSFindFolder(kOnAppropriateDisk, kFrameworksFolderType, true, &frameworksFolderRef);
30 if (err == noErr) {
31 baseURL = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &frameworksFolderRef);
32 if (baseURL == nil) {
33 err = coreFoundationUnknownErr;
34 }
35 }
36
37 if (err == noErr) {
38 bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, framework, false);
39 if (bundleURL == nil) {
40 err = coreFoundationUnknownErr;
41 }
42 }
43
44 if (err == noErr) {
45 *bundlePtr = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL);
46 if (*bundlePtr == nil) {
47 err = coreFoundationUnknownErr;
48 }
49 }
50
51 if (err == noErr) {
52 if (!CFBundleLoadExecutable(*bundlePtr)) {
53 err = coreFoundationUnknownErr;
54 }
55 }
56
57 // Clean up.
58 if (err != noErr && *bundlePtr != nil) {
59 CFRelease(*bundlePtr);
60 *bundlePtr = nil;
61 }
62
63 if (bundleURL != nil) {
64 CFRelease(bundleURL);
65 }
66
67 if (baseURL != nil) {
68 CFRelease(baseURL);
69 }
70
71 return err;
72}
73
74pascal void MacPoller::IdleTimerAction(EventLoopTimerRef, EventLoopIdleTimerMessage inState, void *inUserData)
75{
76 Q_ASSERT(inUserData);
77 switch (inState) {
78 case kEventLoopIdleTimerStarted:
79 case kEventLoopIdleTimerStopped:
80 // Get invoked with this constant at the start of the idle period,
81 // or whenever user activity cancels the idle.
82 ((MacPoller *)inUserData)->m_secondsIdle = 0;
83 ((MacPoller *)inUserData)->triggerResume();
84 break;
85 case kEventLoopIdleTimerIdling:
86 // Called every time the timer fires (i.e. every second).
87 ((MacPoller *)inUserData)->m_secondsIdle++;
88 ((MacPoller *)inUserData)->poll();
89 break;
90 }
91}
92
93// Typedef for the function we're getting back from CFBundleGetFunctionPointerForName.
94typedef OSStatus (*InstallEventLoopIdleTimerPtr)(EventLoopRef inEventLoop,
95 EventTimerInterval inFireDelay,
96 EventTimerInterval inInterval,
97 EventLoopIdleTimerUPP inTimerProc,
98 void *inTimerData,
99 EventLoopTimerRef *outTimer);
100
101MacPoller::MacPoller(QObject *parent)
102 : KAbstractIdleTimePoller(parent)
103 , m_timerRef(0)
104 , m_secondsIdle(0)
105 , m_catch(false)
106{
107}
108
109MacPoller::~MacPoller()
110{
111}
112
113void MacPoller::unloadPoller()
114{
115 RemoveEventLoopTimer(m_timerRef);
116}
117
118bool MacPoller::isAvailable()
119{
120 return true;
121}
122
123bool MacPoller::setUpPoller()
124{
125 // May already be init'ed.
126 if (m_timerRef) {
127 return true;
128 }
129
130 // According to the docs, InstallEventLoopIdleTimer is new in 10.2.
131 // According to the headers, it has been around since 10.0.
132 // One of them is lying. We'll play it safe and weak-link the function.
133
134 // Load the "Carbon.framework" bundle.
135 CFBundleRef carbonBundle;
136
137 if (LoadFrameworkBundle(CFSTR("Carbon.framework"), &carbonBundle) != noErr) {
138 return false;
139 }
140
141 // Load the Mach-O function pointers for the routine we will be using.
142 InstallEventLoopIdleTimerPtr myInstallEventLoopIdleTimer =
143 (InstallEventLoopIdleTimerPtr)CFBundleGetFunctionPointerForName(carbonBundle, CFSTR("InstallEventLoopIdleTimer"));
144
145 if (myInstallEventLoopIdleTimer == 0) {
146 return false;
147 }
148
149 EventLoopIdleTimerUPP timerUPP = NewEventLoopIdleTimerUPP(IdleTimerAction);
150 if ((*myInstallEventLoopIdleTimer)(GetMainEventLoop(), kEventDurationSecond, kEventDurationSecond, timerUPP, this, &m_timerRef)) {
151 return true;
152 }
153
154 return false;
155}
156
157QList<int> MacPoller::timeouts() const
158{
159 return m_timeouts;
160}
161
162void MacPoller::addTimeout(int nextTimeout)
163{
164 m_timeouts.append(nextTimeout);
165 poll();
166}
167
168int MacPoller::poll()
169{
170 int idle = m_secondsIdle * 1000;
171
172 // Check if we reached a timeout..
173 for (int i : std::as_const(m_timeouts)) {
174 if ((i - idle < 1000 && i > idle) || (idle - i < 1000 && idle > i)) {
175 // Bingo!
176 Q_EMIT timeoutReached(i);
177 }
178 }
179
180 return idle;
181}
182
183int MacPoller::forcePollRequest()
184{
185 return poll();
186}
187
188void MacPoller::removeTimeout(int timeout)
189{
190 m_timeouts.removeOne(timeout);
191 poll();
192}
193
194void MacPoller::catchIdleEvent()
195{
196 m_catch = true;
197}
198
199void MacPoller::stopCatchingIdleEvents()
200{
201 m_catch = false;
202}
203
204void MacPoller::triggerResume()
205{
206 if (m_catch) {
207 Q_EMIT resumingFromIdle();
208 stopCatchingIdleEvents();
209 }
210}
211
212void MacPoller::simulateUserActivity()
213{
214 // TODO
215}
216
217#include "moc_macpoller.cpp"
void append(QList< T > &&value)
bool removeOne(const AT &t)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:15:07 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.