Tizen 2.1 release
[platform/core/uifw/e17.git] / src / bin / e_backlight.c
1 #include "e.h"
2 #ifdef HAVE_EEZE
3 # include <Eeze.h>
4 #endif
5
6 // FIXME: backlight should be tied per zone but this implementation is just
7 // a signleton right now as thats 99% of use cases. but api supports
8 // doing more. for now make it work in the singleton
9
10 #define MODE_NONE  -1
11 #define MODE_RANDR 0
12 #define MODE_SYS   1
13
14 static double bl_val = 1.0;
15 static double bl_animval = 1.0;
16 static int sysmode = MODE_NONE;
17 static Ecore_Animator *bl_anim = NULL;
18 static Eina_List *bl_devs = NULL;
19
20 static Ecore_Event_Handler *_e_backlight_handler_config_mode = NULL;
21 static Ecore_Event_Handler *_e_backlight_handler_border_fullscreen = NULL;
22 static Ecore_Event_Handler *_e_backlight_handler_border_unfullscreen = NULL;
23 static Ecore_Event_Handler *_e_backlight_handler_border_remove = NULL;
24 static Ecore_Event_Handler *_e_backlight_handler_border_iconify = NULL;
25 static Ecore_Event_Handler *_e_backlight_handler_border_uniconify = NULL;
26 static Ecore_Event_Handler *_e_backlight_handler_border_desk_set = NULL;
27 static Ecore_Event_Handler *_e_backlight_handler_desk_show = NULL;
28
29 static Ecore_Timer *_e_backlight_timer = NULL;
30
31 static void _e_backlight_update(E_Zone *zone);
32 static void _e_backlight_set(E_Zone *zone, double val);
33 static Eina_Bool _bl_anim(void *data, double pos);
34 static Eina_Bool bl_avail = EINA_FALSE;
35 static Eina_Bool _e_backlight_handler(void *d, int type, void *ev);
36 static Eina_Bool _e_backlight_timer_cb(void *d);
37 #ifdef HAVE_EEZE
38 static const char *bl_sysval = NULL;
39 static Ecore_Event_Handler *bl_sys_exit_handler = NULL;
40 static Ecore_Exe *bl_sys_set_exe = NULL;
41 static Eina_Bool bl_sys_pending_set = EINA_FALSE;
42 static Eina_Bool bl_sys_set_exe_ready = EINA_TRUE;
43
44 static void _bl_sys_find(void);
45 static void _bl_sys_level_get(void);
46 static Eina_Bool _e_bl_cb_exit(void *data __UNUSED__, int type __UNUSED__, void *event);
47 static void _bl_sys_level_set(double val);
48 #endif
49
50 EINTERN int
51 e_backlight_init(void)
52 {
53 #ifdef HAVE_EEZE
54    eeze_init();
55 #endif
56 // why did someone do this? this makes it ONLY work if xrandr has bl support.
57 // WRONG!
58 //   bl_avail = ecore_x_randr_output_backlight_available();
59    bl_avail = EINA_TRUE;
60
61    _e_backlight_handler_config_mode = ecore_event_handler_add
62      (E_EVENT_CONFIG_MODE_CHANGED, _e_backlight_handler, NULL);
63
64    _e_backlight_handler_border_fullscreen = ecore_event_handler_add
65      (E_EVENT_BORDER_FULLSCREEN, _e_backlight_handler, NULL);
66
67    _e_backlight_handler_border_unfullscreen = ecore_event_handler_add
68      (E_EVENT_BORDER_UNFULLSCREEN, _e_backlight_handler, NULL);
69
70    _e_backlight_handler_border_remove = ecore_event_handler_add
71      (E_EVENT_BORDER_REMOVE, _e_backlight_handler, NULL);
72
73    _e_backlight_handler_border_iconify = ecore_event_handler_add
74      (E_EVENT_BORDER_ICONIFY, _e_backlight_handler, NULL);
75
76    _e_backlight_handler_border_uniconify = ecore_event_handler_add
77      (E_EVENT_BORDER_UNICONIFY, _e_backlight_handler, NULL);
78
79    _e_backlight_handler_border_desk_set = ecore_event_handler_add
80      (E_EVENT_BORDER_DESK_SET, _e_backlight_handler, NULL);
81
82    _e_backlight_handler_desk_show = ecore_event_handler_add
83      (E_EVENT_DESK_SHOW, _e_backlight_handler, NULL);
84
85    if (bl_avail)
86      {
87         e_backlight_update();
88         if (!getenv("E_RESTART"))
89           {
90              e_backlight_level_set(NULL, 0.0, 0.0);
91              e_backlight_level_set(NULL, e_config->backlight.normal, 1.0);
92           }
93      }
94    return 1;
95 }
96
97 EINTERN int
98 e_backlight_shutdown(void)
99 {
100    const char *s;
101    
102    if (bl_anim) ecore_animator_del(bl_anim);
103    bl_anim = NULL;
104    EINA_LIST_FREE(bl_devs, s) eina_stringshare_del(s);
105 #ifdef HAVE_EEZE
106    if (bl_sysval) eina_stringshare_del(bl_sysval);
107    bl_sysval = NULL;
108    if (bl_sys_exit_handler) ecore_event_handler_del(bl_sys_exit_handler);
109    bl_sys_exit_handler = NULL;
110    bl_sys_set_exe = NULL;
111    bl_sys_pending_set = EINA_FALSE;
112    eeze_shutdown();
113 #endif
114    if (_e_backlight_handler_config_mode)
115      {
116         ecore_event_handler_del(_e_backlight_handler_config_mode);
117         _e_backlight_handler_config_mode = NULL;
118      }
119
120    if (_e_backlight_handler_border_fullscreen)
121      {
122         ecore_event_handler_del(_e_backlight_handler_border_fullscreen);
123         _e_backlight_handler_border_fullscreen = NULL;
124      }
125
126    if (_e_backlight_handler_border_unfullscreen)
127      {
128         ecore_event_handler_del(_e_backlight_handler_border_unfullscreen);
129         _e_backlight_handler_border_unfullscreen = NULL;
130      }
131
132    if (_e_backlight_handler_border_remove)
133      {
134         ecore_event_handler_del(_e_backlight_handler_border_remove);
135         _e_backlight_handler_border_remove = NULL;
136      }
137
138    if (_e_backlight_handler_border_iconify)
139      {
140         ecore_event_handler_del(_e_backlight_handler_border_iconify);
141         _e_backlight_handler_border_iconify = NULL;
142      }
143
144    if (_e_backlight_handler_border_uniconify)
145      {
146         ecore_event_handler_del(_e_backlight_handler_border_uniconify);
147         _e_backlight_handler_border_uniconify = NULL;
148      }
149
150    if (_e_backlight_handler_border_desk_set)
151      {
152         ecore_event_handler_del(_e_backlight_handler_border_desk_set);
153         _e_backlight_handler_border_desk_set = NULL;
154      }
155
156    if (_e_backlight_handler_desk_show)
157      {
158         ecore_event_handler_del(_e_backlight_handler_desk_show);
159         _e_backlight_handler_desk_show = NULL;
160      }
161    return 1;
162 }
163
164 EAPI Eina_Bool
165 e_backlight_exists(void)
166 {
167    if (sysmode == MODE_NONE) return EINA_FALSE;
168    return EINA_TRUE;
169 }
170
171 EAPI void
172 e_backlight_update(void)
173 {
174    Eina_List *m, *c, *z;
175    E_Manager *man;
176    E_Container *con;
177    E_Zone *zone;
178
179    if (bl_avail == EINA_FALSE) return;
180
181    EINA_LIST_FOREACH(e_manager_list(), m, man)
182      {
183         EINA_LIST_FOREACH(man->containers, c, con)
184           {
185              EINA_LIST_FOREACH(con->zones, z, zone)
186                {
187                   _e_backlight_update(zone);
188                }
189           }
190      }
191
192    /* idle dimming disabled: clear timer */
193    if (!e_config->backlight.idle_dim)
194      {
195         if (_e_backlight_timer)
196           ecore_timer_del(_e_backlight_timer);
197         _e_backlight_timer = NULL;
198         return;
199      }
200    /* dimming enabled, timer active: update interval and reset */
201    if (_e_backlight_timer)
202      {
203         if (e_config->backlight.timer != ecore_timer_interval_get(_e_backlight_timer))
204           ecore_timer_interval_set(_e_backlight_timer, e_config->backlight.timer);
205         ecore_timer_reset(_e_backlight_timer);
206         return;
207      }
208    /* dimming enabled, timer inactive: */
209
210    /* timer is 0 seconds: return */
211    if (!e_config->backlight.timer) return;
212    /* current mode is dimmed: undim */
213    if (e_config->backlight.mode == E_BACKLIGHT_MODE_DIM)
214      e_backlight_mode_set(NULL, E_BACKLIGHT_MODE_NORMAL);
215    _e_backlight_timer = ecore_timer_add(e_config->backlight.timer, _e_backlight_timer_cb, NULL);
216 }
217
218 EAPI void
219 e_backlight_level_set(E_Zone *zone, double val, double tim)
220 {
221    double bl_now;
222    // zone == NULL == everything
223    // set backlight associated with zone to val over period of tim
224    // if tim == 0.0 - then do it instantnly, if time == -1 use some default
225    // transition time
226    if (val < 0.0) val = 0.0;
227    else if (val > 1.0) val = 1.0;
228    if (val == bl_val) return;
229    if (!zone) zone = e_util_zone_current_get(e_manager_current_get());
230    bl_now = bl_val;
231    bl_val = val;
232    if (e_config->backlight.mode != E_BACKLIGHT_MODE_NORMAL) return;
233    if (tim < 0.0) tim = e_config->backlight.transition;
234    if (tim == 0.0)
235      {
236         if (bl_anim)
237           {
238              ecore_animator_del(bl_anim);
239              bl_anim = NULL;
240           }
241         _e_backlight_set(zone, val);
242        return;
243      }
244    if (bl_anim) ecore_animator_del(bl_anim);
245    bl_anim = ecore_animator_timeline_add(tim, _bl_anim, zone);
246    bl_animval = bl_now;
247 }
248
249 EAPI double
250 e_backlight_level_get(E_Zone *zone __UNUSED__)
251 {
252    // zone == NULL == everything
253    return bl_val;
254 }
255
256 EAPI void
257 e_backlight_mode_set(E_Zone *zone, E_Backlight_Mode mode)
258 {
259    // zone == NULL == everything
260    if (e_config->backlight.mode == mode) return;
261    e_config->backlight.mode = mode;
262    if      (e_config->backlight.mode == E_BACKLIGHT_MODE_NORMAL)
263       e_backlight_level_set(zone, bl_val, -1.0);
264    else if (e_config->backlight.mode == E_BACKLIGHT_MODE_OFF)
265       e_backlight_level_set(zone, 0.0, -1.0);
266    else if (e_config->backlight.mode == E_BACKLIGHT_MODE_DIM)
267       e_backlight_level_set(zone, e_config->backlight.dim, -1.0);
268    else if (e_config->backlight.mode == E_BACKLIGHT_MODE_MAX)
269       e_backlight_level_set(zone, 1.0, -1.0);
270 }
271
272 EAPI E_Backlight_Mode
273 e_backlight_mode_get(E_Zone *zone __UNUSED__)
274 {
275    // zone == NULL == everything
276    return e_config->backlight.mode;
277 }
278
279 EAPI const Eina_List *
280 e_backlight_devices_get(void)
281 {
282    return bl_devs;
283 }
284
285 /* local subsystem functions */
286
287 static Eina_Bool
288 _e_backlight_handler(void *d __UNUSED__, int type __UNUSED__, void *ev __UNUSED__)
289 {
290    e_backlight_update();
291    return ECORE_CALLBACK_PASS_ON;
292 }
293
294 static Eina_Bool
295 _e_backlight_timer_cb(void *d __UNUSED__)
296 {
297    e_backlight_mode_set(NULL, E_BACKLIGHT_MODE_DIM);
298    _e_backlight_timer = NULL;
299    return EINA_FALSE;
300 }
301
302 static void
303 _e_backlight_update(E_Zone *zone)
304 {
305    double x_bl = -1.0;
306    Ecore_X_Window root;
307    Ecore_X_Randr_Output *out;
308    int i, num = 0;
309
310    root = zone->container->manager->root;
311    // try randr
312    out = ecore_x_randr_window_outputs_get(root, &num);
313    if ((out) && (num > 0) && (ecore_x_randr_output_backlight_available()))
314      {
315         char *name;
316         const char *s;
317         Eina_Bool gotten = EINA_FALSE;
318         
319         EINA_LIST_FREE(bl_devs, s) eina_stringshare_del(s);
320         for (i = 0; i < num; i++)
321           {
322              name = ecore_x_randr_output_name_get(root, out[i], NULL);
323              bl_devs = eina_list_append(bl_devs, eina_stringshare_add(name));
324              if ((name) && (e_config->backlight.sysdev) &&
325                  (!strcmp(name, e_config->backlight.sysdev)))
326                {
327                   x_bl = ecore_x_randr_output_backlight_level_get(root, out[i]);
328                   gotten = EINA_TRUE;
329                }
330              if (name) free(name);
331           }
332         if (!gotten)
333           x_bl = ecore_x_randr_output_backlight_level_get(root, out[0]);
334      }
335    if (out) free(out);
336    if (x_bl >= 0.0)
337      {
338         bl_val = x_bl;
339         sysmode = MODE_RANDR;
340         return;
341      }
342 #ifdef HAVE_EEZE
343    _bl_sys_find();
344    if (bl_sysval)
345      {
346         sysmode = MODE_SYS;
347         _bl_sys_level_get();
348         return;
349      }
350 #endif
351 }
352
353 static void
354 _e_backlight_set(E_Zone *zone, double val)
355 {
356    if (sysmode == MODE_RANDR)
357      {
358         Ecore_X_Window root;
359         Ecore_X_Randr_Output *out;
360         int num = 0, i;
361         char *name;
362
363         root = zone->container->manager->root;
364         out = ecore_x_randr_window_outputs_get(root, &num);
365         if ((out) && (num > 0))
366           {
367              Eina_Bool gotten = EINA_FALSE;
368              for (i = 0; i < num; i++)
369                {
370                   name = ecore_x_randr_output_name_get(root, out[i], NULL);
371                   if (name)
372                     {
373                        if ((e_config->backlight.sysdev) &&
374                            (!strcmp(name, e_config->backlight.sysdev)))
375                          {
376                             ecore_x_randr_output_backlight_level_set(root, out[i], val);
377                             gotten = EINA_TRUE;
378                          }
379                        free(name);
380                     }
381                }
382              if (!gotten)
383                {
384                   for (i = 0; i < num; i++)
385                     ecore_x_randr_output_backlight_level_set(root, out[i], val);
386                }
387           }
388         if (out) free(out);
389      }
390 #ifdef HAVE_EEZE
391    else if (sysmode == MODE_SYS)
392      {
393         if (bl_sysval)
394           {
395              _bl_sys_level_set(val);
396           }
397      }
398 #endif
399 }
400
401 static Eina_Bool
402 _bl_anim(void *data, double pos)
403 {
404    E_Zone *zone = data;
405    double v;
406
407    // FIXME: if zone is deleted while anim going... bad things.
408    pos = ecore_animator_pos_map(pos, ECORE_POS_MAP_DECELERATE, 0.0, 0.0);
409    v = (bl_animval * (1.0 - pos)) + (bl_val *pos);
410    _e_backlight_set(zone, v);
411    if (pos >= 1.0)
412      {
413         bl_anim = NULL;
414         return EINA_FALSE;
415      }
416    return EINA_TRUE;
417 }
418
419 #ifdef HAVE_EEZE
420 static void
421 _bl_sys_find(void)
422 {
423    Eina_List *l, *devs, *pdevs = NULL;
424    Eina_Bool use;
425    const char *f, *s;
426    int v;
427
428    devs = eeze_udev_find_by_filter("backlight", NULL, NULL);
429    if (!devs)
430      {
431         /* FIXME: need to make this more precise so we don't set keyboard LEDs or something */
432         devs = eeze_udev_find_by_filter("leds", NULL, NULL);
433         if (!devs) return;
434      }
435    if (eina_list_count(devs) > 1)
436      {
437         /* prefer backlights of type "firmware" where available */
438         EINA_LIST_FOREACH(devs, l, f)
439           {
440              s = eeze_udev_syspath_get_sysattr(f, "type");
441              use = (s && (!strcmp(s, "firmware")));
442              eina_stringshare_del(s);
443              if (!use) continue;
444              s = eeze_udev_syspath_get_sysattr(f, "brightness");
445              if (!s) continue;
446              v = atoi(s);
447              eina_stringshare_del(s);
448              if (v < 0) continue;
449              pdevs = eina_list_append(pdevs, eina_stringshare_add(f));
450              eina_stringshare_del(f);
451              l->data = NULL;
452           }
453         EINA_LIST_FOREACH(devs, l, f)
454           {
455              if (!l->data) continue;
456              s = eeze_udev_syspath_get_sysattr(f, "brightness");
457              if (!s) continue;
458              v = atoi(s);
459              eina_stringshare_del(s);
460              if (v < 0) continue;
461              pdevs = eina_list_append(pdevs, eina_stringshare_add(f));
462           }
463      }
464    if (!pdevs)
465      {
466         /* add the other backlight or led's if none found */
467         EINA_LIST_FOREACH(devs, l, f)
468           {
469              use = EINA_FALSE;
470              s = eeze_udev_syspath_get_sysattr(f, "brightness");
471              if (!s) continue;
472              v = atoi(s);
473              eina_stringshare_del(s);
474              if (v < 0) continue;
475              pdevs = eina_list_append(pdevs, eina_stringshare_add(f));
476           }
477      }
478    /* clear out original devs list now we've filtered */
479    EINA_LIST_FREE(devs, f)
480      {
481         if (f) eina_stringshare_del(f);
482      }
483    /* clear out old configured bl sysval */
484    if (bl_sysval)
485      {
486         eina_stringshare_del(bl_sysval);
487         bl_sysval = NULL;
488      }
489    EINA_LIST_FREE(bl_devs, s) eina_stringshare_del(s);
490    /* if configured backlight is there - use it, or if not use first */
491    EINA_LIST_FOREACH(pdevs, l, f)
492      {
493         bl_devs = eina_list_append(bl_devs, eina_stringshare_add(f));
494          if (!bl_sysval)
495           {
496              if ((e_config->backlight.sysdev) &&
497                  (!strcmp(e_config->backlight.sysdev, f)))
498                bl_sysval = eina_stringshare_add(f);
499              else
500                bl_sysval = eina_stringshare_add(f);
501           }
502      }
503    if (!bl_sysval)
504      {
505         EINA_LIST_FOREACH(pdevs, l, f)
506           {
507              if (!bl_sysval)
508                bl_sysval = eina_stringshare_add(f);
509           }
510      }
511    /* clear out preferred devs list */
512    EINA_LIST_FREE(pdevs, f)
513      {
514         eina_stringshare_del(f);
515      }
516 }
517
518 static void
519 _bl_sys_level_get(void)
520 {
521    int maxval, val;
522    const char *str;
523
524    str = eeze_udev_syspath_get_sysattr(bl_sysval, "max_brightness");
525    if (!str) return;
526
527    maxval = atoi(str);
528    eina_stringshare_del(str);
529    if (maxval <= 0) maxval = 255;
530    str = eeze_udev_syspath_get_sysattr(bl_sysval, "brightness");
531    if (!str) return;
532
533    val = atoi(str);
534    eina_stringshare_del(str);
535    if ((val >= 0) && (val <= maxval))
536      bl_val = (double)val / (double)maxval;
537 // printf("GET: %i/%i (%1.3f)\n", val, maxval, bl_val);
538 }
539
540 static Eina_Bool
541 _e_bl_cb_ext_delay(void *data __UNUSED__)
542 {
543    bl_sys_set_exe_ready = EINA_TRUE;
544    if (bl_sys_pending_set)
545      {
546         bl_sys_pending_set = EINA_FALSE;
547         _bl_sys_level_set(bl_val);
548      }
549    return EINA_FALSE;
550 }
551
552 static Eina_Bool
553 _e_bl_cb_exit(void *data __UNUSED__, int type __UNUSED__, void *event)
554 {
555    Ecore_Exe_Event_Del *ev;
556
557    ev = event;
558    if (ev->exe == bl_sys_set_exe)
559      {
560         bl_sys_set_exe_ready = EINA_FALSE;
561         bl_sys_set_exe = NULL;
562         ecore_timer_add(0.1, _e_bl_cb_ext_delay, NULL);
563      }
564    return ECORE_CALLBACK_RENEW;
565 }
566
567 static void
568 _bl_sys_level_set(double val)
569 {
570    char buf[PATH_MAX];
571
572    if (!bl_sys_exit_handler)
573       bl_sys_exit_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
574                                                     _e_bl_cb_exit, NULL);
575    if ((bl_sys_set_exe) || (!bl_sys_set_exe_ready))
576      {
577         bl_sys_pending_set = EINA_TRUE;
578         return;
579      }
580 //   printf("SET: %1.3f\n", val);
581    snprintf(buf, sizeof(buf),
582             "%s/enlightenment/utils/enlightenment_backlight %i %s",
583             e_prefix_lib_get(), (int)(val * 1000.0), bl_sysval);
584    bl_sys_set_exe = ecore_exe_run(buf, NULL);
585 }
586 #endif