1 #include <cstdlib>
2 #include <sstream>
3 using namespace std;
4 
5 #include <sys/time.h>
6 #include <unistd.h>
7 
8 #include <CoreFoundation/CoreFoundation.h>
9 #include <CoreServices/CoreServices.h>
10 #include <IOKit/IOKitLib.h>
11 
12 #include "config.h"
13 
14 #include "keywords.h"
15 #include "Options.h"
16 #include "xpUtil.h"
17 
18 #include "TimerMacAqua.h"
19 
TimerMacAqua(const int w,const unsigned long h,const unsigned long i)20 TimerMacAqua::TimerMacAqua(const int w, const unsigned long h,
21                            const unsigned long i) : Timer(w, h, i)
22 {
23 }
24 
~TimerMacAqua()25 TimerMacAqua::~TimerMacAqua()
26 {
27 }
28 
29 // returns false if the program should exit after this sleep
30 bool
Sleep()31 TimerMacAqua::Sleep()
32 {
33     // Sleep until the next update
34     gettimeofday(&currentTime_, NULL);
35     if (!SleepForTime(nextUpdate_ - currentTime_.tv_sec))
36         return(false);
37 
38     // If the display has not been idle for idlewait_
39     // milliseconds, keep sleeping.  Check every second until the
40     // display has been idle for long enough.
41     if (idlewait_ > 0)
42     {
43         unsigned long idle = GetSystemIdleTime();
44         Options *options = Options::getInstance();
45         if (options->Verbosity() > 0)
46         {
47             ostringstream msg;
48             msg << "Idle time is " << idle/1000 << " second";
49             if (idle/1000 != 1) msg << "s";
50             msg << endl;
51             xpMsg(msg.str(), __FILE__, __LINE__);
52         }
53         while (idle < idlewait_)
54         {
55             gettimeofday(&currentTime_, NULL);
56             if (!SleepForTime((idlewait_ - idle) / 1000))
57                 return(false);
58             idle = GetSystemIdleTime();
59         }
60     }
61 
62     // If the display has been idle for longer than hibernate_
63     // milliseconds, keep sleeping.  Check every second until
64     // something happens.
65     if (hibernate_ > 0)
66     {
67         unsigned long idle = GetSystemIdleTime();
68         Options *options = Options::getInstance();
69         if (options->Verbosity() > 0 && idle > hibernate_)
70             xpMsg("Hibernating ...\n", __FILE__, __LINE__);
71 
72         while (idle > hibernate_)
73         {
74             if (!SleepForTime(1))
75                 return(false);
76             idle = GetSystemIdleTime();
77         }
78     }
79     return(true);
80 }
81 
82 // return the system idle time in milliseconds This code is based on
83 // "idler", found at
84 // http://www.macosxlabs.org/tools_and_scripts/script_archive/script_archive.html
85 // Their copyright notice follows:
86 
87 /*****************************************
88  * idler.c
89  *
90  * Uses IOKit to figure out the idle time of the system. The idle time
91  * is stored as a property of the IOHIDSystem class; the name is
92  * HIDIdleTime. Stored as a 64-bit int, measured in ns.
93  *
94  * The program itself just prints to stdout the time that the computer has
95  * been idle in seconds.
96  *
97  * Compile with gcc -Wall -framework IOKit -framework Carbon idler.c -o
98  * idler
99  *
100  * Copyright (c) 2003, Stanford University
101  * All rights reserved.
102  *
103  * Redistribution and use in source and binary forms, with or without
104  * modification, are permitted provided that the following conditions are
105  * met:
106  * Redistributions of source code must retain the above copyright notice,
107  * this list of conditions and the following disclaimer.
108  *
109  * Redistributions in binary form must reproduce the above copyright notice,
110  * this list of conditions and the following disclaimer in the documentation
111  * and/or other materials provided with the distribution.
112  *
113  * Neither the name of Stanford University nor the names of its contributors
114  * may be used to endorse or promote products derived from this software
115  * without specific prior written permission.
116  *
117  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
118  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
119  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
120  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
121  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
122  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
123  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
124  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
125  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
126  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
127  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
128  */
129 unsigned long
GetSystemIdleTime()130 TimerMacAqua::GetSystemIdleTime()
131 {
132     unsigned long idle;
133 
134     mach_port_t masterPort;
135     io_iterator_t iter;
136     io_registry_entry_t curObj;
137 
138     IOMasterPort(MACH_PORT_NULL, &masterPort);
139 
140     /* Get IOHIDSystem */
141     IOServiceGetMatchingServices(masterPort,
142                                  IOServiceMatching("IOHIDSystem"),
143                                  &iter);
144     if (iter == 0)
145     {
146         xpWarn("Error accessing IOHIDSystem\n", __FILE__, __LINE__);
147     }
148 
149     curObj = IOIteratorNext(iter);
150 
151     if (curObj == 0)
152     {
153         xpWarn("Iterator's empty!\n", __FILE__, __LINE__);
154     }
155 
156     CFMutableDictionaryRef properties = 0;
157     CFTypeRef obj;
158 
159     if (IORegistryEntryCreateCFProperties(curObj, &properties,
160                                           kCFAllocatorDefault, 0)
161         == KERN_SUCCESS && properties != NULL)
162     {
163 
164         obj = CFDictionaryGetValue(properties, CFSTR("HIDIdleTime"));
165         CFRetain(obj);
166     }
167     else
168     {
169         xpWarn("Couldn't grab properties of system\n", __FILE__, __LINE__);
170         obj = NULL;
171     }
172 
173     if (obj)
174     {
175         uint64_t tHandle;
176 
177         CFTypeID type = CFGetTypeID(obj);
178 
179         if (type == CFDataGetTypeID())
180         {
181             CFDataGetBytes((CFDataRef) obj,
182                            CFRangeMake(0, sizeof(tHandle)),
183                            (UInt8*) &tHandle);
184         }
185         else if (type == CFNumberGetTypeID())
186         {
187             CFNumberGetValue((CFNumberRef)obj,
188                              kCFNumberSInt64Type,
189                              &tHandle);
190         }
191         else
192         {
193             ostringstream errMsg;
194             errMsg << (int) type << ": unsupported type\n";
195             xpWarn(errMsg.str(), __FILE__, __LINE__);
196         }
197 
198         CFRelease(obj);
199 
200         // tHandle is in nanoseconds, we want milliseconds
201         idle = static_cast<unsigned long> (tHandle / 1e6);
202     }
203     else
204     {
205         xpWarn("Can't find idle time\n", __FILE__, __LINE__);
206     }
207 
208     /* Release our resources */
209     IOObjectRelease(curObj);
210     IOObjectRelease(iter);
211     CFRelease((CFTypeRef)properties);
212 
213     return(idle);
214 }
215