upload tizen1.0 source
[framework/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 E_Backlight_Mode bl_mode = E_BACKLIGHT_MODE_NORMAL;
17 static int sysmode = MODE_NONE;
18 static Ecore_Animator *bl_anim = 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    if (bl_anim) ecore_animator_del(bl_anim);
101    bl_anim = NULL;
102 #ifdef HAVE_EEZE
103    if (bl_sysval) eina_stringshare_del(bl_sysval);
104    bl_sysval = NULL;
105    if (bl_sys_exit_handler) ecore_event_handler_del(bl_sys_exit_handler);
106    bl_sys_exit_handler = NULL;
107    bl_sys_set_exe = NULL;
108    bl_sys_pending_set = EINA_FALSE;
109    eeze_shutdown();
110 #endif
111    if (_e_backlight_handler_config_mode)
112      {
113         ecore_event_handler_del(_e_backlight_handler_config_mode);
114         _e_backlight_handler_config_mode = NULL;
115      }
116
117    if (_e_backlight_handler_border_fullscreen)
118      {
119         ecore_event_handler_del(_e_backlight_handler_border_fullscreen);
120         _e_backlight_handler_border_fullscreen = NULL;
121      }
122
123    if (_e_backlight_handler_border_unfullscreen)
124      {
125         ecore_event_handler_del(_e_backlight_handler_border_unfullscreen);
126         _e_backlight_handler_border_unfullscreen = NULL;
127      }
128
129    if (_e_backlight_handler_border_remove)
130      {
131         ecore_event_handler_del(_e_backlight_handler_border_remove);
132         _e_backlight_handler_border_remove = NULL;
133      }
134
135    if (_e_backlight_handler_border_iconify)
136      {
137         ecore_event_handler_del(_e_backlight_handler_border_iconify);
138         _e_backlight_handler_border_iconify = NULL;
139      }
140
141    if (_e_backlight_handler_border_uniconify)
142      {
143         ecore_event_handler_del(_e_backlight_handler_border_uniconify);
144         _e_backlight_handler_border_uniconify = NULL;
145      }
146
147    if (_e_backlight_handler_border_desk_set)
148      {
149         ecore_event_handler_del(_e_backlight_handler_border_desk_set);
150         _e_backlight_handler_border_desk_set = NULL;
151      }
152
153    if (_e_backlight_handler_desk_show)
154      {
155         ecore_event_handler_del(_e_backlight_handler_desk_show);
156         _e_backlight_handler_desk_show = NULL;
157      }
158    return 1;
159 }
160
161 EAPI Eina_Bool
162 e_backlight_exists(void)
163 {
164    if (sysmode == MODE_NONE) return EINA_FALSE;
165    return EINA_TRUE;
166 }
167
168 EAPI void
169 e_backlight_update(void)
170 {
171    Eina_List *m, *c, *z;
172    E_Manager *man;
173    E_Container *con;
174    E_Zone *zone;
175
176    if (bl_avail == EINA_FALSE) return;
177
178    EINA_LIST_FOREACH(e_manager_list(), m, man)
179      {
180         EINA_LIST_FOREACH(man->containers, c, con)
181           {
182              EINA_LIST_FOREACH(con->zones, z, zone)
183                {
184                   _e_backlight_update(zone);
185                }
186           }
187      }
188
189    /* idle dimming disabled: clear timer */
190    if (!e_config->backlight.idle_dim)
191      {
192         if (_e_backlight_timer)
193           ecore_timer_del(_e_backlight_timer);
194         _e_backlight_timer = NULL;
195         return;
196      }
197    /* dimming enabled, timer active: update interval and reset */
198    if (_e_backlight_timer)
199      {
200         if (e_config->backlight.timer != ecore_timer_interval_get(_e_backlight_timer))
201           ecore_timer_interval_set(_e_backlight_timer, e_config->backlight.timer);
202         ecore_timer_reset(_e_backlight_timer);
203         return;
204      }
205    /* dimming enabled, timer inactive: */
206
207    /* timer is 0 seconds: return */
208    if (!e_config->backlight.timer) return;
209    /* current mode is dimmed: undim */
210    if (bl_mode == E_BACKLIGHT_MODE_DIM)
211      e_backlight_mode_set(NULL, E_BACKLIGHT_MODE_NORMAL);
212    _e_backlight_timer = ecore_timer_add(e_config->backlight.timer, _e_backlight_timer_cb, NULL);
213 }
214
215 EAPI void
216 e_backlight_level_set(E_Zone *zone, double val, double tim)
217 {
218    double bl_now;
219    // zone == NULL == everything
220    // set backlight associated with zone to val over period of tim
221    // if tim == 0.0 - then do it instantnly, if time == -1 use some default
222    // transition time
223    if (val < 0.0) val = 0.0;
224    else if (val > 1.0) val = 1.0;
225    if (val == bl_val) return;
226    if (!zone) zone = e_util_zone_current_get(e_manager_current_get());
227    bl_now = bl_val;
228    bl_val = val;
229    if (bl_mode != E_BACKLIGHT_MODE_NORMAL) return;
230    if (tim < 0.0) tim = e_config->backlight.transition;
231    if (tim == 0.0)
232      {
233         if (bl_anim)
234           {
235              ecore_animator_del(bl_anim);
236              bl_anim = NULL;
237           }
238         _e_backlight_set(zone, val);
239        return;
240      }
241    if (bl_anim) ecore_animator_del(bl_anim);
242    bl_anim = ecore_animator_timeline_add(tim, _bl_anim, zone);
243    bl_animval = bl_now;
244 }
245
246 EAPI double
247 e_backlight_level_get(E_Zone *zone __UNUSED__)
248 {
249    // zone == NULL == everything
250    return bl_val;
251 }
252
253 EAPI void
254 e_backlight_mode_set(E_Zone *zone, E_Backlight_Mode mode)
255 {
256    // zone == NULL == everything
257    if (bl_mode == mode) return;
258    bl_mode = mode;
259    if      (bl_mode == E_BACKLIGHT_MODE_NORMAL)
260       e_backlight_level_set(zone, bl_val, -1.0);
261    else if (bl_mode == E_BACKLIGHT_MODE_OFF)
262       e_backlight_level_set(zone, 0.0, -1.0);
263    else if (bl_mode == E_BACKLIGHT_MODE_DIM)
264       e_backlight_level_set(zone, e_config->backlight.dim, -1.0);
265    else if (bl_mode == E_BACKLIGHT_MODE_MAX)
266       e_backlight_level_set(zone, 1.0, -1.0);
267 }
268
269 EAPI E_Backlight_Mode
270 e_backlight_mode_get(E_Zone *zone __UNUSED__)
271 {
272    // zone == NULL == everything
273    return bl_mode;
274 }
275
276 /* local subsystem functions */
277
278 static Eina_Bool
279 _e_backlight_handler(void *d __UNUSED__, int type __UNUSED__, void *ev __UNUSED__)
280 {
281    e_backlight_update();
282    return ECORE_CALLBACK_PASS_ON;
283 }
284
285 static Eina_Bool
286 _e_backlight_timer_cb(void *d __UNUSED__)
287 {
288    e_backlight_mode_set(NULL, E_BACKLIGHT_MODE_DIM);
289    _e_backlight_timer = NULL;
290    return EINA_FALSE;
291 }
292
293 static void
294 _e_backlight_update(E_Zone *zone)
295 {
296    double x_bl = -1.0;
297    Ecore_X_Window root;
298    Ecore_X_Randr_Output *out;
299    int num = 0;
300
301    root = zone->container->manager->root;
302    // try randr
303    out = ecore_x_randr_window_outputs_get(root, &num);
304    if ((out) && (num > 0) && (ecore_x_randr_output_backlight_available()))
305       x_bl = ecore_x_randr_output_backlight_level_get(root, out[0]);
306    if (out) free(out);
307    if (x_bl >= 0.0)
308      {
309         bl_val = x_bl;
310         sysmode = MODE_RANDR;
311      }
312 #ifdef HAVE_EEZE
313    else
314      {
315         _bl_sys_find();
316         if (bl_sysval)
317           {
318              sysmode = MODE_SYS;
319              _bl_sys_level_get();
320           }
321      }
322 #endif
323 }
324
325 static void
326 _e_backlight_set(E_Zone *zone, double val)
327 {
328    if (sysmode == MODE_RANDR)
329      {
330         Ecore_X_Window root;
331         Ecore_X_Randr_Output *out;
332         int num = 0;
333         
334         root = zone->container->manager->root;
335         out = ecore_x_randr_window_outputs_get(root, &num);
336         if ((out) && (num > 0))
337           {
338              ecore_x_randr_output_backlight_level_set(root, out[0], val);
339           }
340         if (out) free(out);
341      }
342 #ifdef HAVE_EEZE
343    else if (sysmode == MODE_SYS)
344      {
345         if (bl_sysval)
346           {
347              _bl_sys_level_set(val);
348           }
349      }
350 #endif
351 }
352
353 static Eina_Bool
354 _bl_anim(void *data, double pos)
355 {
356    E_Zone *zone = data;
357    double v;
358    
359    // FIXME: if zone is deleted while anim going... bad things.
360    pos = ecore_animator_pos_map(pos, ECORE_POS_MAP_DECELERATE, 0.0, 0.0);
361    v = (bl_animval * (1.0 - pos)) + (bl_val *pos);
362    _e_backlight_set(zone, v);
363    if (pos >= 1.0)
364      {
365         bl_anim = NULL;
366         return EINA_FALSE;
367      }
368    return EINA_TRUE;
369 }
370
371 #ifdef HAVE_EEZE
372 static void
373 _bl_sys_find(void)
374 {
375    Eina_List *devs;
376    const char *f;
377
378    devs = eeze_udev_find_by_filter("backlight", NULL, NULL);
379    if (!devs)
380      {
381         /* FIXME: need to make this more precise so we don't set keyboard LEDs or something */
382         devs = eeze_udev_find_by_filter("leds", NULL, NULL);
383         if (!devs) return;
384      }
385    if (eina_list_count(devs) > 1)
386      {
387         const char *s = NULL;
388         Eina_List *l;
389         Eina_Bool use = EINA_FALSE;
390
391         /* prefer backlights of type "firmware" where available */
392         EINA_LIST_FOREACH(devs, l, f)
393           {
394              s = eeze_udev_syspath_get_sysattr(f, "type");
395              use = (s && (!strcmp(s, "firmware")));
396              eina_stringshare_del(s);
397              if (!use) continue;
398              l->data = NULL;
399              eina_stringshare_del(bl_sysval);
400              bl_sysval = f;
401              EINA_LIST_FREE(devs, f)
402                eina_stringshare_del(f);
403              return;
404           }
405      }
406    EINA_LIST_FREE(devs, f)
407      {
408         eina_stringshare_replace(&bl_sysval, NULL);
409         bl_sysval = f;
410      }
411 }
412
413 static void
414 _bl_sys_level_get(void)
415 {
416    int maxval, val;
417    const char *str;
418
419    str = eeze_udev_syspath_get_sysattr(bl_sysval, "max_brightness");
420    if (!str) return;
421
422    maxval = atoi(str);
423    eina_stringshare_del(str);
424    if (maxval <= 0) maxval = 255;
425    str = eeze_udev_syspath_get_sysattr(bl_sysval, "brightness");
426    if (!str) return;
427
428    val = atoi(str);
429    eina_stringshare_del(str);
430    if ((val >= 0) && (val <= maxval))
431      bl_val = (double)val / (double)maxval;
432 // printf("GET: %i/%i (%1.3f)\n", val, maxval, bl_val);
433 }
434
435 static Eina_Bool
436 _e_bl_cb_ext_delay(void *data __UNUSED__)
437 {
438    bl_sys_set_exe_ready = EINA_TRUE;
439    if (bl_sys_pending_set)
440      {
441         bl_sys_pending_set = EINA_FALSE;
442         _bl_sys_level_set(bl_val);
443      }
444    return EINA_FALSE;
445 }
446
447 static Eina_Bool
448 _e_bl_cb_exit(void *data __UNUSED__, int type __UNUSED__, void *event)
449 {
450    Ecore_Exe_Event_Del *ev;
451    
452    ev = event;
453    if (ev->exe == bl_sys_set_exe)
454      {
455         bl_sys_set_exe_ready = EINA_FALSE;
456         bl_sys_set_exe = NULL;
457         ecore_timer_add(0.1, _e_bl_cb_ext_delay, NULL);
458      }
459    return ECORE_CALLBACK_RENEW;
460 }
461
462 static void
463 _bl_sys_level_set(double val)
464 {
465    char buf[PATH_MAX];
466    
467    if (!bl_sys_exit_handler)
468       bl_sys_exit_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
469                                                     _e_bl_cb_exit, NULL);
470    if ((bl_sys_set_exe) || (!bl_sys_set_exe_ready))
471      {
472         bl_sys_pending_set = EINA_TRUE;
473         return;
474      }
475 //   printf("SET: %1.3f\n", val);
476    snprintf(buf, sizeof(buf), 
477             "%s/enlightenment/utils/enlightenment_backlight %i", 
478             e_prefix_lib_get(), (int)(val * 1000.0));
479    bl_sys_set_exe = ecore_exe_run(buf, NULL);
480 }
481 #endif