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?
13 static 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 
74 pascal 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.
94 typedef OSStatus (*InstallEventLoopIdleTimerPtr)(EventLoopRef inEventLoop,
95  EventTimerInterval inFireDelay,
96  EventTimerInterval inInterval,
97  EventLoopIdleTimerUPP inTimerProc,
98  void *inTimerData,
99  EventLoopTimerRef *outTimer);
100 
101 MacPoller::MacPoller(QObject *parent)
102  : AbstractSystemPoller(parent)
103  , m_timerRef(0)
104  , m_secondsIdle(0)
105  , m_catch(false)
106 {
107 }
108 
109 MacPoller::~MacPoller()
110 {
111 }
112 
113 void MacPoller::unloadPoller()
114 {
115  RemoveEventLoopTimer(m_timerRef);
116 }
117 
118 bool MacPoller::isAvailable()
119 {
120  return true;
121 }
122 
123 bool 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 
157 QList<int> MacPoller::timeouts() const
158 {
159  return m_timeouts;
160 }
161 
162 void MacPoller::addTimeout(int nextTimeout)
163 {
164  m_timeouts.append(nextTimeout);
165  poll();
166 }
167 
168 int 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!
177  }
178  }
179 
180  return idle;
181 }
182 
183 int MacPoller::forcePollRequest()
184 {
185  return poll();
186 }
187 
188 void MacPoller::removeTimeout(int timeout)
189 {
190  m_timeouts.removeOne(timeout);
191  poll();
192 }
193 
194 void MacPoller::catchIdleEvent()
195 {
196  m_catch = true;
197 }
198 
199 void MacPoller::stopCatchingIdleEvents()
200 {
201  m_catch = false;
202 }
203 
204 void MacPoller::triggerResume()
205 {
206  if (m_catch) {
208  stopCatchingIdleEvents();
209  }
210 }
211 
212 void MacPoller::simulateUserActivity()
213 {
214  // TODO
215 }
void append(const T &value)
void timeoutReached(int identifier, int msec)
Triggered when the system has been idle for x milliseconds, identified by the previously set timeout...
Q_EMITQ_EMIT
void resumingFromIdle()
Triggered, if KIdleTime is catching resume events, when the system resumes from an idle state...
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Jan 22 2022 22:45:47 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.