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