|
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
|
2 // Use of this source code is governed by a BSD-style license that can be |
|
3 // found in the LICENSE file. |
|
4 |
|
5 #include "base/idle_timer.h" |
|
6 |
|
7 // We may not want to port idle_timer to Linux, but we have implemented it |
|
8 // anyway. Define this to 1 to enable the Linux idle timer and then add the |
|
9 // libs that need to be linked (Xss). |
|
10 #define ENABLE_XSS_SUPPORT 0 |
|
11 |
|
12 #if defined(OS_MACOSX) |
|
13 #include <ApplicationServices/ApplicationServices.h> |
|
14 #endif |
|
15 |
|
16 #if defined(OS_LINUX) && ENABLE_XSS_SUPPORT |
|
17 // We may not want to port idle_timer to Linux, but we have implemented it |
|
18 // anyway. Remove the 0 above if we want it. |
|
19 #include <gdk/gdkx.h> |
|
20 #include <X11/extensions/scrnsaver.h> |
|
21 #include "base/lazy_instance.h" |
|
22 #include "base/thread_local.h" |
|
23 #endif |
|
24 |
|
25 #include "base/message_loop.h" |
|
26 #include "base/time.h" |
|
27 |
|
28 namespace base { |
|
29 |
|
30 #if defined(OS_WIN) |
|
31 bool OSIdleTimeSource(int32_t *milliseconds_interval_since_last_event) { |
|
32 LASTINPUTINFO lastInputInfo; |
|
33 lastInputInfo.cbSize = sizeof(lastInputInfo); |
|
34 if (GetLastInputInfo(&lastInputInfo) == 0) { |
|
35 return false; |
|
36 } |
|
37 int32_t last_input_time = lastInputInfo.dwTime; |
|
38 |
|
39 // Note: On Windows GetLastInputInfo returns a 32bit value which rolls over |
|
40 // ~49days. |
|
41 int32_t current_time = GetTickCount(); |
|
42 int32_t delta = current_time - last_input_time; |
|
43 // delta will go negative if we've been idle for 2GB of ticks. |
|
44 if (delta < 0) |
|
45 delta = -delta; |
|
46 *milliseconds_interval_since_last_event = delta; |
|
47 return true; |
|
48 } |
|
49 #elif defined(OS_MACOSX) |
|
50 bool OSIdleTimeSource(int32_t *milliseconds_interval_since_last_event) { |
|
51 *milliseconds_interval_since_last_event = |
|
52 CGEventSourceSecondsSinceLastEventType( |
|
53 kCGEventSourceStateCombinedSessionState, |
|
54 kCGAnyInputEventType) * 1000.0; |
|
55 return true; |
|
56 } |
|
57 #elif defined(OS_LINUX) && ENABLE_XSS_SUPPORT |
|
58 class IdleState { |
|
59 public: |
|
60 IdleState() { |
|
61 int event_base, error_base; |
|
62 have_idle_info_ = XScreenSaverQueryExtension(GDK_DISPLAY(), &event_base, |
|
63 &error_base); |
|
64 if (have_idle_info_) |
|
65 idle_info_.Set(XScreenSaverAllocInfo()); |
|
66 } |
|
67 |
|
68 ~IdleState() { |
|
69 if (idle_info_.Get()) { |
|
70 XFree(idle_info_.Get()); |
|
71 idle_info_.~ThreadLocalPointer(); |
|
72 } |
|
73 } |
|
74 |
|
75 int32_t IdleTime() { |
|
76 if (have_idle_info_ && idle_info_.Get()) { |
|
77 XScreenSaverQueryInfo(GDK_DISPLAY(), GDK_ROOT_WINDOW(), |
|
78 idle_info_.Get()); |
|
79 return idle_info_.Get()->idle; |
|
80 } |
|
81 return -1; |
|
82 } |
|
83 |
|
84 private: |
|
85 bool have_idle_info_; |
|
86 ThreadLocalPointer<XScreenSaverInfo> idle_info_; |
|
87 |
|
88 DISALLOW_COPY_AND_ASSIGN(IdleState); |
|
89 }; |
|
90 |
|
91 bool OSIdleTimeSource(int32_t* milliseconds_interval_since_last_event) { |
|
92 static LazyInstance<IdleState> state_instance(base::LINKER_INITIALIZED); |
|
93 IdleState* state = state_instance.Pointer(); |
|
94 int32_t idle_time = state->IdleTime(); |
|
95 if (0 < idle_time) { |
|
96 *milliseconds_interval_since_last_event = idle_time; |
|
97 return true; |
|
98 } |
|
99 return false; |
|
100 } |
|
101 #endif |
|
102 |
|
103 IdleTimer::IdleTimer(TimeDelta idle_time, bool repeat) |
|
104 : idle_interval_(idle_time), |
|
105 repeat_(repeat), |
|
106 idle_time_source_(OSIdleTimeSource) { |
|
107 DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()) << |
|
108 "Requires a thread that processes Windows UI events"; |
|
109 } |
|
110 |
|
111 IdleTimer::~IdleTimer() { |
|
112 Stop(); |
|
113 } |
|
114 |
|
115 void IdleTimer::Start() { |
|
116 StartTimer(); |
|
117 } |
|
118 |
|
119 void IdleTimer::Stop() { |
|
120 timer_.Stop(); |
|
121 } |
|
122 |
|
123 void IdleTimer::Run() { |
|
124 // Verify we can fire the idle timer. |
|
125 if (TimeUntilIdle().InMilliseconds() <= 0) { |
|
126 OnIdle(); |
|
127 last_time_fired_ = Time::Now(); |
|
128 } |
|
129 Stop(); |
|
130 StartTimer(); // Restart the timer for next run. |
|
131 } |
|
132 |
|
133 void IdleTimer::StartTimer() { |
|
134 DCHECK(!timer_.IsRunning()); |
|
135 TimeDelta delay = TimeUntilIdle(); |
|
136 if (delay.InMilliseconds() < 0) |
|
137 delay = TimeDelta(); |
|
138 timer_.Start(delay, this, &IdleTimer::Run); |
|
139 } |
|
140 |
|
141 TimeDelta IdleTimer::CurrentIdleTime() { |
|
142 int32_t interval = 0; |
|
143 if (idle_time_source_(&interval)) { |
|
144 return TimeDelta::FromMilliseconds(interval); |
|
145 } |
|
146 NOTREACHED(); |
|
147 return TimeDelta::FromMilliseconds(0); |
|
148 } |
|
149 |
|
150 TimeDelta IdleTimer::TimeUntilIdle() { |
|
151 TimeDelta time_since_last_fire = Time::Now() - last_time_fired_; |
|
152 TimeDelta current_idle_time = CurrentIdleTime(); |
|
153 if (current_idle_time > time_since_last_fire) { |
|
154 if (repeat_) |
|
155 return idle_interval_ - time_since_last_fire; |
|
156 return idle_interval_; |
|
157 } |
|
158 return idle_interval_ - current_idle_time; |
|
159 } |
|
160 |
|
161 } // namespace base |