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