1 #include "e.h"
2 #include <sys/select.h>
3
4 struct _E_Powersave_Deferred_Action
5 {
6 void (*func)(void *data);
7 const void *data;
8 unsigned char delete_me E_BITFIELD;
9 };
10
11 struct _E_Powersave_Sleeper
12 {
13 Ecore_Pipe *pipe;
14 int fd;
15 };
16
17 /* local subsystem functions */
18 static void _e_powersave_sleeper_cb_dummy(void *data EINA_UNUSED, void *buffer EINA_UNUSED, unsigned int bytes EINA_UNUSED);
19 static Eina_Bool _e_powersave_cb_deferred_timer(void *data);
20 static void _e_powersave_mode_eval(void);
21 static void _e_powersave_event_update_free(void *data EINA_UNUSED, void *event);
22 static void _e_powersave_event_change_send(E_Powersave_Mode mode);
23 static void _e_powersave_sleepers_wake(void);
24
25 /* local subsystem globals */
26 E_API int E_EVENT_POWERSAVE_UPDATE = 0;
27 E_API int E_EVENT_POWERSAVE_CONFIG_UPDATE = 0;
28 static int walking_deferred_actions = 0;
29 static Eina_List *deferred_actions = NULL;
30 static Ecore_Timer *deferred_timer = NULL;
31 static E_Powersave_Mode powersave_mode = E_POWERSAVE_MODE_LOW;
32 static E_Powersave_Mode powersave_mode_force = E_POWERSAVE_MODE_NONE;
33 static double defer_time = 5.0;
34 static Eina_Bool powersave_force = EINA_FALSE;
35 static Eina_List *powersave_sleepers = NULL;
36 static Eina_Bool powersave_deferred_suspend = EINA_FALSE;
37 static Eina_Bool powersave_deferred_hibernate = EINA_FALSE;
38
39 /* externally accessible functions */
40 EINTERN int
e_powersave_init(void)41 e_powersave_init(void)
42 {
43 _e_powersave_mode_eval();
44 E_EVENT_POWERSAVE_UPDATE = ecore_event_type_new();
45 E_EVENT_POWERSAVE_CONFIG_UPDATE = ecore_event_type_new();
46 return 1;
47 }
48
49 EINTERN int
e_powersave_shutdown(void)50 e_powersave_shutdown(void)
51 {
52 return 1;
53 }
54
55 E_API E_Powersave_Deferred_Action *
e_powersave_deferred_action_add(void (* func)(void * data),const void * data)56 e_powersave_deferred_action_add(void (*func)(void *data), const void *data)
57 {
58 E_Powersave_Deferred_Action *pa;
59
60 pa = calloc(1, sizeof(E_Powersave_Deferred_Action));
61 if (!pa) return NULL;
62 if (deferred_timer) ecore_timer_del(deferred_timer);
63 deferred_timer = ecore_timer_loop_add(defer_time,
64 _e_powersave_cb_deferred_timer,
65 NULL);
66 pa->func = func;
67 pa->data = data;
68 deferred_actions = eina_list_append(deferred_actions, pa);
69 return pa;
70 }
71
72 E_API void
e_powersave_deferred_action_del(E_Powersave_Deferred_Action * pa)73 e_powersave_deferred_action_del(E_Powersave_Deferred_Action *pa)
74 {
75 if (walking_deferred_actions)
76 {
77 pa->delete_me = 1;
78 return;
79 }
80 else
81 {
82 deferred_actions = eina_list_remove(deferred_actions, pa);
83 free(pa);
84 if (!deferred_actions)
85 {
86 if (deferred_timer)
87 {
88 ecore_timer_del(deferred_timer);
89 deferred_timer = NULL;
90 }
91 }
92 }
93 }
94
95 E_API void
e_powersave_mode_set(E_Powersave_Mode mode)96 e_powersave_mode_set(E_Powersave_Mode mode)
97 {
98 if (mode < e_config->powersave.min) mode = e_config->powersave.min;
99 else if (mode > e_config->powersave.max) mode = e_config->powersave.max;
100
101 if (powersave_mode == mode) return;
102 powersave_mode = mode;
103
104 if (powersave_force) return;
105 _e_powersave_event_change_send(powersave_mode);
106 _e_powersave_mode_eval();
107 }
108
109 E_API E_Powersave_Mode
e_powersave_mode_get(void)110 e_powersave_mode_get(void)
111 {
112 if (powersave_force) return powersave_mode_force;
113 return powersave_mode;
114 }
115
116 E_API void
e_powersave_mode_force(E_Powersave_Mode mode)117 e_powersave_mode_force(E_Powersave_Mode mode)
118 {
119 if (mode == powersave_mode_force) return;
120 powersave_force = EINA_TRUE;
121 powersave_mode_force = mode;
122 _e_powersave_event_change_send(powersave_mode_force);
123 _e_powersave_mode_eval();
124 }
125
126 E_API void
e_powersave_mode_unforce(void)127 e_powersave_mode_unforce(void)
128 {
129 if (!powersave_force) return;
130 powersave_force = EINA_FALSE;
131 if (powersave_mode_force != powersave_mode)
132 {
133 _e_powersave_event_change_send(powersave_mode);
134 _e_powersave_mode_eval();
135 }
136 powersave_mode_force = E_POWERSAVE_MODE_NONE;
137 }
138
139 E_API E_Powersave_Sleeper *
e_powersave_sleeper_new(void)140 e_powersave_sleeper_new(void)
141 {
142 E_Powersave_Sleeper *sleeper;
143
144 sleeper = E_NEW(E_Powersave_Sleeper, 1);
145 sleeper->pipe = ecore_pipe_add(_e_powersave_sleeper_cb_dummy, NULL);
146 if (!sleeper->pipe)
147 {
148 eina_freeq_ptr_add(eina_freeq_main_get(), sleeper, free, sizeof(*sleeper));
149 return NULL;
150 }
151 sleeper->fd = ecore_pipe_read_fd(sleeper->pipe);
152 ecore_pipe_freeze(sleeper->pipe);
153 powersave_sleepers = eina_list_append(powersave_sleepers, sleeper);
154 return (E_Powersave_Sleeper *)sleeper;
155 }
156
157 E_API void
e_powersave_sleeper_free(E_Powersave_Sleeper * sleeper)158 e_powersave_sleeper_free(E_Powersave_Sleeper *sleeper)
159 {
160 if (!sleeper) return;
161 ecore_pipe_del(sleeper->pipe);
162 powersave_sleepers = eina_list_remove(powersave_sleepers, sleeper);
163 eina_freeq_ptr_add(eina_freeq_main_get(), sleeper, free, sizeof(*sleeper));
164 }
165
166 E_API void
e_powersave_sleeper_sleep(E_Powersave_Sleeper * sleeper,int poll_interval)167 e_powersave_sleeper_sleep(E_Powersave_Sleeper *sleeper, int poll_interval)
168 {
169 double timf;
170 unsigned int tim;
171 fd_set rfds, wfds, exfds;
172 struct timeval tv;
173 int ret;
174 char buf[1] = { 1 };
175
176 if (!sleeper) return;
177 if (e_powersave_mode_get() == E_POWERSAVE_MODE_FREEZE) timf = 3600;
178 else timf = (double)poll_interval / 8.0;
179 FD_ZERO(&rfds);
180 FD_ZERO(&wfds);
181 FD_ZERO(&exfds);
182 FD_SET(sleeper->fd, &rfds);
183
184 tim = ((timf - fmod(ecore_time_get(), timf)) * 1000000.0);
185 tv.tv_sec = tim / 1000000;
186 tv.tv_usec = tim % 1000000;
187 for (;;)
188 {
189 ret = select(sleeper->fd + 1, &rfds, &wfds, &exfds, &tv);
190 if ((ret == 1) && (FD_ISSET(sleeper->fd, &rfds)))
191 {
192 if (read(sleeper->fd, buf, 1) < 0)
193 fprintf(stderr, "%s: ERROR READING FROM FD\n", __func__);
194 return;
195 }
196 else if (ret == 0)
197 {
198 return;
199 }
200 }
201 }
202
203 E_API void
e_powersave_defer_suspend(void)204 e_powersave_defer_suspend(void)
205 {
206 powersave_deferred_suspend = EINA_TRUE;
207 }
208
209 E_API void
e_powersave_defer_hibernate(void)210 e_powersave_defer_hibernate(void)
211 {
212 powersave_deferred_hibernate = EINA_TRUE;
213 }
214
215 E_API void
e_powersave_defer_cancel(void)216 e_powersave_defer_cancel(void)
217 {
218 powersave_deferred_suspend = EINA_FALSE;
219 powersave_deferred_hibernate = EINA_FALSE;
220 }
221
222 /* local subsystem functions */
223
224 static void
_e_powersave_sleepers_wake(void)225 _e_powersave_sleepers_wake(void)
226 {
227 E_Powersave_Sleeper *sleeper;
228 Eina_List *l;
229 char buf[1] = { 1 };
230
231 EINA_LIST_FOREACH(powersave_sleepers, l, sleeper)
232 {
233 if (write(ecore_pipe_write_fd(sleeper->pipe), buf, 1) < 0)
234 fprintf(stderr, "%s: ERROR WRITING TO FD\n", __func__);
235 ecore_pipe_write(sleeper->pipe, buf, 1);
236 }
237 }
238
239 static void
_e_powersave_sleeper_cb_dummy(void * data EINA_UNUSED,void * buffer EINA_UNUSED,unsigned int bytes EINA_UNUSED)240 _e_powersave_sleeper_cb_dummy(void *data EINA_UNUSED, void *buffer EINA_UNUSED, unsigned int bytes EINA_UNUSED)
241 {
242 }
243
244 static Eina_Bool
_e_powersave_cb_deferred_timer(void * data EINA_UNUSED)245 _e_powersave_cb_deferred_timer(void *data EINA_UNUSED)
246 {
247 E_Powersave_Deferred_Action *pa;
248
249 walking_deferred_actions++;
250 EINA_LIST_FREE(deferred_actions, pa)
251 {
252 if (!pa->delete_me) pa->func((void *)pa->data);
253 free(pa);
254 }
255 walking_deferred_actions--;
256 if (!deferred_actions) deferred_timer = NULL;
257 return ECORE_CALLBACK_CANCEL;
258 }
259
260 static void
_e_powersave_mode_eval(void)261 _e_powersave_mode_eval(void)
262 {
263 double t = 0.0;
264 E_Powersave_Mode mode;
265
266 if (powersave_force) mode = powersave_mode_force;
267 else mode = powersave_mode;
268
269 switch (mode)
270 {
271 case E_POWERSAVE_MODE_NONE:
272 t = e_config->powersave.none; /* time to defer "power expensive" activities */
273 break;
274
275 case E_POWERSAVE_MODE_LOW:
276 t = e_config->powersave.low;
277 break;
278
279 case E_POWERSAVE_MODE_MEDIUM:
280 t = e_config->powersave.medium;
281 break;
282
283 case E_POWERSAVE_MODE_HIGH:
284 t = e_config->powersave.high;
285 break;
286
287 case E_POWERSAVE_MODE_EXTREME:
288 t = e_config->powersave.extreme;
289 break;
290
291 case E_POWERSAVE_MODE_FREEZE:
292 t = 3600;
293 break;
294
295 default:
296 return;
297 break;
298 }
299 if (!EINA_DBL_EQ(t, defer_time))
300 {
301 if (deferred_timer) ecore_timer_del(deferred_timer);
302 deferred_timer = ecore_timer_loop_add(defer_time,
303 _e_powersave_cb_deferred_timer,
304 NULL);
305 defer_time = t;
306 }
307 }
308
309 static void
_e_powersave_event_update_free(void * data EINA_UNUSED,void * event)310 _e_powersave_event_update_free(void *data EINA_UNUSED, void *event)
311 {
312 E_Powersave_Mode mode;
313
314 if (powersave_force) mode = powersave_mode_force;
315 else mode = powersave_mode;
316 free(event);
317
318 if (mode > E_POWERSAVE_MODE_LOW)
319 {
320 if (powersave_deferred_hibernate)
321 e_sys_action_do(E_SYS_HIBERNATE, NULL);
322 else if (powersave_deferred_suspend)
323 e_sys_action_do(E_SYS_SUSPEND, NULL);
324 }
325 powersave_deferred_hibernate = EINA_FALSE;
326 powersave_deferred_suspend = EINA_FALSE;
327 }
328
329 static void
_e_powersave_event_change_send(E_Powersave_Mode mode)330 _e_powersave_event_change_send(E_Powersave_Mode mode)
331 {
332 E_Event_Powersave_Update *ev;
333
334 printf("CHANGE PW SAVE MODE TO %i / %i\n",
335 (int)mode, E_POWERSAVE_MODE_EXTREME);
336 ev = E_NEW(E_Event_Powersave_Update, 1);
337 ev->mode = mode;
338 ecore_event_add(E_EVENT_POWERSAVE_UPDATE, ev, _e_powersave_event_update_free, NULL);
339 _e_powersave_sleepers_wake();
340 }
341