1 #include "e.h"
2 #include "e_mod_main.h"
3 
4 #if defined(__FreeBSD__) || defined(__DragonFly__)
5 #include <sys/types.h>
6 #include <sys/sysctl.h>
7 #endif
8 
9 #ifdef __OpenBSD__
10 #include <sys/types.h>
11 #include <sys/sysctl.h>
12 #include <sys/sensors.h>
13 #endif
14 
15 
16 /* gadcon requirements */
17 static E_Gadcon_Client *_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style);
18 static void _gc_shutdown(E_Gadcon_Client *gcc);
19 static void _gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient);
20 static const char *_gc_label(const E_Gadcon_Client_Class *client_class);
21 static Evas_Object *_gc_icon(const E_Gadcon_Client_Class *client_class, Evas *evas);
22 static const char *_gc_id_new(const E_Gadcon_Client_Class *client_class);
23 /* and actually define the gadcon class that this module provides (just 1) */
24 static const E_Gadcon_Client_Class _gadcon_class =
25 {
26    GADCON_CLIENT_CLASS_VERSION, "temperature",
27      {
28         _gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL,
29         e_gadcon_site_is_not_toolbar
30      },
31    E_GADCON_CLIENT_STYLE_PLAIN
32 };
33 
34 /* actual module specifics */
35 
36 static void _temperature_face_cb_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
37 
38 static void _temperature_face_cb_menu_configure(void *data, E_Menu *m, E_Menu_Item *mi);
39 
40 static Eina_Bool _temperature_face_shutdown(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *hdata, void *fdata EINA_UNUSED);
41 static Eina_Bool _temperature_face_id_max(const Eina_Hash *hash EINA_UNUSED, const void *key, void *hdata EINA_UNUSED, void *fdata);
42 
43 static E_Config_DD *conf_edd = NULL;
44 static E_Config_DD *conf_face_edd = NULL;
45 
46 static int uuid = 0;
47 
48 static Config *temperature_config = NULL;
49 
50 static void
_temperature_thread_free(Tempthread * tth)51 _temperature_thread_free(Tempthread *tth)
52 {
53 #if defined(HAVE_EEZE)
54    const char *s;
55 #endif
56    eina_stringshare_del(tth->sensor_name);
57    eina_stringshare_del(tth->sensor_path);
58 #if defined(HAVE_EEZE)
59    EINA_LIST_FREE(tth->tempdevs, s) eina_stringshare_del(s);
60 #endif
61    e_powersave_sleeper_free(tth->sleeper);
62    free(tth->extn);
63    free(tth);
64 }
65 
66 static void
_temperature_face_level_set(Config_Face * inst,double level)67 _temperature_face_level_set(Config_Face *inst, double level)
68 {
69    Edje_Message_Float msg;
70 
71    if (level < 0.0) level = 0.0;
72    else if (level > 1.0) level = 1.0;
73    msg.val = level;
74    edje_object_message_send(inst->o_temp, EDJE_MESSAGE_FLOAT, 1, &msg);
75 }
76 
77 static void
_temperature_apply(Config_Face * inst,int temp)78 _temperature_apply(Config_Face *inst, int temp)
79 {
80    char buf[64];
81 
82    if (inst->temp == temp) return;
83    inst->temp = temp;
84    if (temp != -999)
85      {
86         if (inst->units == FAHRENHEIT) temp = (temp * 9.0 / 5.0) + 32;
87 
88         if (!inst->have_temp)
89           {
90              /* enable therm object */
91              edje_object_signal_emit(inst->o_temp, "e,state,known", "");
92              inst->have_temp = EINA_TRUE;
93           }
94         if (inst->units == FAHRENHEIT)
95           snprintf(buf, sizeof(buf), "%i°F", temp);
96         else
97           snprintf(buf, sizeof(buf), "%i°C", temp);
98 
99         _temperature_face_level_set(inst,
100                                     (double)(temp - inst->low) /
101                                     (double)(inst->high - inst->low));
102         edje_object_part_text_set(inst->o_temp, "e.text.reading", buf);
103      }
104    else
105      {
106         if (inst->have_temp)
107           {
108              /* disable therm object */
109              edje_object_signal_emit(inst->o_temp, "e,state,unknown", "");
110              edje_object_part_text_set(inst->o_temp, "e.text.reading", "N/A");
111              _temperature_face_level_set(inst, 0.5);
112              inst->have_temp = EINA_FALSE;
113           }
114      }
115 }
116 
117 #ifdef HAVE_EEZE
118 static Eina_Bool
_temperature_udev_poll(void * data)119 _temperature_udev_poll(void *data)
120 {
121    Tempthread *tth = data;
122    int temp = temperature_udev_get(tth);
123 
124    _temperature_apply(tth->inst, temp);
125    return EINA_TRUE;
126 }
127 #endif
128 
129 static E_Gadcon_Client *
_gc_init(E_Gadcon * gc,const char * name,const char * id,const char * style)130 _gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style)
131 {
132    Evas_Object *o;
133    E_Gadcon_Client *gcc;
134    Config_Face *inst;
135 
136    inst = eina_hash_find(temperature_config->faces, id);
137    if (!inst)
138      {
139         inst = E_NEW(Config_Face, 1);
140         inst->id = eina_stringshare_add(id);
141         inst->poll_interval = 128;
142         inst->low = 30;
143         inst->high = 80;
144         inst->sensor_type = SENSOR_TYPE_NONE;
145         inst->sensor_name = NULL;
146         inst->temp = -900;
147         inst->units = CELSIUS;
148 #ifdef HAVE_EEZE
149         inst->backend = UDEV;
150 #endif
151         if (!temperature_config->faces)
152           temperature_config->faces = eina_hash_string_superfast_new(NULL);
153         eina_hash_direct_add(temperature_config->faces, inst->id, inst);
154      }
155    if (!inst->id) inst->id = eina_stringshare_add(id);
156    E_CONFIG_LIMIT(inst->poll_interval, 1, 1024);
157    E_CONFIG_LIMIT(inst->low, 0, 100);
158    E_CONFIG_LIMIT(inst->high, 0, 220);
159    E_CONFIG_LIMIT(inst->units, CELSIUS, FAHRENHEIT);
160 #ifdef HAVE_EEZE
161    E_CONFIG_LIMIT(inst->backend, TEMPGET, UDEV);
162 #endif
163 
164    o = edje_object_add(gc->evas);
165    e_theme_edje_object_set(o, "base/theme/modules/temperature",
166                            "e/modules/temperature/main");
167 
168    gcc = e_gadcon_client_new(gc, name, id, style, o);
169    gcc->data = inst;
170 
171    inst->gcc = gcc;
172    inst->o_temp = o;
173    inst->module = temperature_config->module;
174    inst->have_temp = EINA_FALSE;
175    temperature_face_update_config(inst);
176 
177    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN,
178                                   _temperature_face_cb_mouse_down, inst);
179    return gcc;
180 }
181 
182 static void
_gc_shutdown(E_Gadcon_Client * gcc)183 _gc_shutdown(E_Gadcon_Client *gcc)
184 {
185    Config_Face *inst;
186 
187    inst = gcc->data;
188 
189    if (inst->o_temp) evas_object_del(inst->o_temp);
190    inst->o_temp = NULL;
191    if (inst->config_dialog) e_object_del(E_OBJECT(inst->config_dialog));
192    inst->config_dialog = NULL;
193 }
194 
195 static void
_gc_orient(E_Gadcon_Client * gcc,E_Gadcon_Orient orient EINA_UNUSED)196 _gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient EINA_UNUSED)
197 {
198    e_gadcon_client_aspect_set(gcc, 16, 16);
199    e_gadcon_client_min_size_set(gcc, 16, 16);
200 }
201 
202 static const char *
_gc_label(const E_Gadcon_Client_Class * client_class EINA_UNUSED)203 _gc_label(const E_Gadcon_Client_Class *client_class EINA_UNUSED)
204 {
205    return _("Temperature");
206 }
207 
208 static Evas_Object *
_gc_icon(const E_Gadcon_Client_Class * client_class EINA_UNUSED,Evas * evas)209 _gc_icon(const E_Gadcon_Client_Class *client_class EINA_UNUSED, Evas *evas)
210 {
211    Evas_Object *o;
212    char buf[PATH_MAX];
213 
214    o = edje_object_add(evas);
215    snprintf(buf, sizeof(buf), "%s/e-module-temperature.edj",
216             e_module_dir_get(temperature_config->module));
217    edje_object_file_set(o, buf, "icon");
218    return o;
219 }
220 
221 static const char *
_gc_id_new(const E_Gadcon_Client_Class * client_class EINA_UNUSED)222 _gc_id_new(const E_Gadcon_Client_Class *client_class EINA_UNUSED)
223 {
224    Config_Face *inst;
225    char id[128];
226 
227    snprintf(id, sizeof(id), "%s.%d", _gadcon_class.name, ++uuid);
228 
229    inst = E_NEW(Config_Face, 1);
230    inst->id = eina_stringshare_add(id);
231    inst->poll_interval = 128;
232    inst->low = 30;
233    inst->high = 80;
234    inst->sensor_type = SENSOR_TYPE_NONE;
235    inst->sensor_name = NULL;
236    inst->units = CELSIUS;
237 #ifdef HAVE_EEZE
238    inst->backend = TEMPGET;
239 #endif
240    if (!temperature_config->faces)
241      temperature_config->faces = eina_hash_string_superfast_new(NULL);
242    eina_hash_direct_add(temperature_config->faces, inst->id, inst);
243    return inst->id;
244 }
245 
246 static void
_temperature_face_cb_mouse_down(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)247 _temperature_face_cb_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
248 {
249    Config_Face *inst;
250    Evas_Event_Mouse_Down *ev;
251 
252    inst = data;
253    ev = event_info;
254    if (ev->button == 3)
255      {
256         E_Menu *m;
257         E_Menu_Item *mi;
258         int cx, cy;
259 
260         m = e_menu_new();
261         mi = e_menu_item_new(m);
262         e_menu_item_label_set(mi, _("Settings"));
263         e_util_menu_item_theme_icon_set(mi, "configure");
264         e_menu_item_callback_set(mi, _temperature_face_cb_menu_configure, inst);
265 
266         m = e_gadcon_client_util_menu_items_append(inst->gcc, m, 0);
267 
268         e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &cx, &cy, NULL, NULL);
269         e_menu_activate_mouse(m, e_zone_current_get(),
270                               cx + ev->output.x, cy + ev->output.y, 1, 1,
271                               E_MENU_POP_DIRECTION_AUTO, ev->timestamp);
272         evas_event_feed_mouse_up(inst->gcc->gadcon->evas, ev->button,
273                                  EVAS_BUTTON_NONE, ev->timestamp, NULL);
274      }
275 }
276 
277 static void
_temperature_face_cb_menu_configure(void * data,E_Menu * m EINA_UNUSED,E_Menu_Item * mi EINA_UNUSED)278 _temperature_face_cb_menu_configure(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED)
279 {
280    Config_Face *inst;
281 
282    inst = data;
283    if (inst->config_dialog) return;
284    config_temperature_module(inst);
285 }
286 
287 static Eina_Bool
_temperature_face_shutdown(const Eina_Hash * hash EINA_UNUSED,const void * key EINA_UNUSED,void * hdata,void * fdata EINA_UNUSED)288 _temperature_face_shutdown(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *hdata, void *fdata EINA_UNUSED)
289 {
290    Config_Face *inst;
291 
292    inst = hdata;
293    if (inst->th) ecore_thread_cancel(inst->th);
294    if (inst->sensor_name) eina_stringshare_del(inst->sensor_name);
295    if (inst->id) eina_stringshare_del(inst->id);
296 #ifdef HAVE_EEZE
297    if (inst->poller)
298      {
299         ecore_poller_del(inst->poller);
300         _temperature_thread_free(inst->tth);
301      }
302 #endif
303    E_FREE(inst);
304    return EINA_TRUE;
305 }
306 
307 static Eina_Bool
_temperature_face_id_max(const Eina_Hash * hash EINA_UNUSED,const void * key,void * hdata EINA_UNUSED,void * fdata)308 _temperature_face_id_max(const Eina_Hash *hash EINA_UNUSED, const void *key, void *hdata EINA_UNUSED, void *fdata)
309 {
310    const char *p;
311    int *max;
312    int num = -1;
313 
314    max = fdata;
315    p = strrchr(key, '.');
316    if (p) num = atoi(p + 1);
317    if (num > *max) *max = num;
318    return EINA_TRUE;
319 }
320 
321 static void
_temperature_check_main(void * data,Ecore_Thread * th)322 _temperature_check_main(void *data, Ecore_Thread *th)
323 {
324    Tempthread *tth = data;
325    int ptemp = -500, temp;
326 
327    for (;;)
328      {
329         if (ecore_thread_check(th)) break;
330         temp = temperature_tempget_get(tth);
331         if (ptemp != temp) ecore_thread_feedback(th, (void *)((long)temp));
332         ptemp = temp;
333         e_powersave_sleeper_sleep(tth->sleeper, tth->poll_interval);
334         if (ecore_thread_check(th)) break;
335      }
336 }
337 
338 static void
_temperature_check_notify(void * data,Ecore_Thread * th,void * msg)339 _temperature_check_notify(void *data, Ecore_Thread *th, void *msg)
340 {
341    Tempthread *tth  = data;
342    Config_Face *inst = tth->inst;
343    int temp = (int)((long)msg);
344 
345    if (th != inst->th) return;
346    _temperature_apply(inst, temp);
347 }
348 
349 static void
_temperature_check_done(void * data,Ecore_Thread * th EINA_UNUSED)350 _temperature_check_done(void *data, Ecore_Thread *th EINA_UNUSED)
351 {
352    _temperature_thread_free(data);
353 }
354 
355 void
temperature_face_update_config(Config_Face * inst)356 temperature_face_update_config(Config_Face *inst)
357 {
358    Tempthread *tth;
359 
360    if (inst->th) ecore_thread_cancel(inst->th);
361 
362    tth = calloc(1, sizeof(Tempthread));
363    tth->poll_interval = inst->poll_interval;
364    tth->sensor_type = inst->sensor_type;
365    tth->inst = inst;
366    tth->sleeper = e_powersave_sleeper_new();
367    if (inst->sensor_name)
368      tth->sensor_name = eina_stringshare_add(inst->sensor_name);
369 
370 #ifdef HAVE_EEZE
371    if (inst->backend != TEMPGET)
372      {
373         inst->poller = ecore_poller_add(ECORE_POLLER_CORE, inst->poll_interval,
374                                         _temperature_udev_poll, tth);
375         inst->tth = tth;
376      }
377    else
378 #endif
379      inst->th = ecore_thread_feedback_run(_temperature_check_main,
380                                           _temperature_check_notify,
381                                           _temperature_check_done,
382                                           _temperature_check_done,
383                                           tth, EINA_TRUE);
384 }
385 
386 /* module setup */
387 E_API E_Module_Api e_modapi =
388 {
389    E_MODULE_API_VERSION,
390      "Temperature"
391 };
392 
393 E_API void *
e_modapi_init(E_Module * m)394 e_modapi_init(E_Module *m)
395 {
396    conf_face_edd = E_CONFIG_DD_NEW("Temperature_Config_Face", Config_Face);
397 #undef T
398 #undef D
399 #define T Config_Face
400 #define D conf_face_edd
401    E_CONFIG_VAL(D, T, id, STR);
402    E_CONFIG_VAL(D, T, poll_interval, INT);
403    E_CONFIG_VAL(D, T, low, INT);
404    E_CONFIG_VAL(D, T, high, INT);
405    E_CONFIG_VAL(D, T, sensor_type, INT);
406 #ifdef HAVE_EEZE
407    E_CONFIG_VAL(D, T, backend, INT);
408 #endif
409    E_CONFIG_VAL(D, T, sensor_name, STR);
410    E_CONFIG_VAL(D, T, units, INT);
411 
412    conf_edd = E_CONFIG_DD_NEW("Temperature_Config", Config);
413 #undef T
414 #undef D
415 #define T Config
416 #define D conf_edd
417    E_CONFIG_HASH(D, T, faces, conf_face_edd);
418 
419    temperature_config = e_config_domain_load("module.temperature", conf_edd);
420    if (!temperature_config)
421      temperature_config = E_NEW(Config, 1);
422    else if (temperature_config->faces)
423      eina_hash_foreach(temperature_config->faces, _temperature_face_id_max, &uuid);
424    temperature_config->module = m;
425 
426    e_gadcon_provider_register(&_gadcon_class);
427    return m;
428 }
429 
430 E_API int
e_modapi_shutdown(E_Module * m EINA_UNUSED)431 e_modapi_shutdown(E_Module *m EINA_UNUSED)
432 {
433    e_gadcon_provider_unregister(&_gadcon_class);
434    if (temperature_config->faces)
435      eina_hash_foreach(temperature_config->faces, _temperature_face_shutdown, NULL);
436    eina_hash_free(temperature_config->faces);
437    free(temperature_config);
438    temperature_config = NULL;
439    E_CONFIG_DD_FREE(conf_face_edd);
440    E_CONFIG_DD_FREE(conf_edd);
441    return 1;
442 }
443 
444 E_API int
e_modapi_save(E_Module * m EINA_UNUSED)445 e_modapi_save(E_Module *m EINA_UNUSED)
446 {
447    e_config_domain_save("module.temperature", conf_edd, temperature_config);
448    return 1;
449 }
450