diff options
author | Michaël Bouchaud (yoz) <yoz@efl.so> | 2017-01-07 11:19:10 +0100 |
---|---|---|
committer | Michael Bouchaud(yoz) <yoz@efl.so> | 2017-03-16 11:27:11 +0100 |
commit | 51124fb3965abd4a1358e55da3302ea334cee3e3 (patch) | |
tree | cf9ca7214152f9f731dbc6983f2ea90632a8d52e | |
parent | 9745890a37036091d5dec320fecda7ed4c6bdb6c (diff) | |
download | enlightenment-devs/yoz/weather.tar.gz |
weather: Add a new weather widgetdevs/yoz/weather
-rw-r--r-- | configure.ac | 15 | ||||
-rw-r--r-- | src/bin/e_module.c | 1 | ||||
-rw-r--r-- | src/modules/Makefile.mk | 2 | ||||
-rw-r--r-- | src/modules/Makefile_weather.mk | 29 | ||||
-rw-r--r-- | src/modules/weather/config.c | 197 | ||||
-rw-r--r-- | src/modules/weather/e-module-weather.edj | bin | 0 -> 1186281 bytes | |||
-rw-r--r-- | src/modules/weather/mod.c | 104 | ||||
-rw-r--r-- | src/modules/weather/module.desktop.in | 7 | ||||
-rw-r--r-- | src/modules/weather/plugin.c | 234 | ||||
-rw-r--r-- | src/modules/weather/plugin.h | 33 | ||||
-rw-r--r-- | src/modules/weather/plugin_openweathermap.c | 540 | ||||
-rw-r--r-- | src/modules/weather/plugin_openweathermap.h | 6 | ||||
-rw-r--r-- | src/modules/weather/theme.edj | bin | 0 -> 1151169 bytes | |||
-rw-r--r-- | src/modules/weather/weather.c | 811 | ||||
-rw-r--r-- | src/modules/weather/weather.h | 190 |
15 files changed, 2169 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index 672e8e89ce..463e763dec 100644 --- a/configure.ac +++ b/configure.ac @@ -457,6 +457,19 @@ AC_ARG_ENABLE([wayland], AC_MSG_CHECKING([whether wayland support is enabled]) AC_MSG_RESULT([${e_cv_want_wayland_only}]) +# define the openweathermap api key + +AC_ARG_WITH([openweathermap-api-key], + [AC_HELP_STRING([--with-openweathermap-api-key=OPENWEATHERMAP_API_KEY], [specify a custom openweathermap api key])], + [ + v=$withval; + openweathermap_api_key=$v + echo " Enlightenment openweathermap api key explicitly set to "$openweathermap_api_key; + ], + [openweathermap_api_key=81947d7198f4efa1cc88080be5cc039a]) +AC_SUBST(openweathermap_api_key) + + # doxygen program for documentation building EFL_CHECK_DOXYGEN([build_doc="yes"], [build_doc="no"]) @@ -915,6 +928,7 @@ AC_E_OPTIONAL_MODULE([xwayland], $have_wayland_dep, [CHECK_MODULE_XWAYLAND]) AC_E_OPTIONAL_MODULE([wireless], true) AC_E_OPTIONAL_MODULE([time], true) AC_E_OPTIONAL_MODULE([sysinfo], true) +AC_E_OPTIONAL_MODULE([weather], true) if test "x${HAVE_WL_X11}" != "xyes" && test "x${have_wayland}" = "xyes" && test "x${HAVE_XWAYLAND}" != "xyes"; then AC_DEFINE_UNQUOTED([HAVE_WAYLAND_ONLY],[1],[enable wayland-only version of enlightenment]) @@ -1145,6 +1159,7 @@ src/modules/packagekit/module.desktop src/modules/wl_desktop_shell/module.desktop src/modules/wireless/module.desktop src/modules/time/module.desktop +src/modules/weather/module.desktop src/modules/luncher/module.desktop src/modules/sysinfo/module.desktop data/xsession/enlightenment.desktop diff --git a/src/bin/e_module.c b/src/bin/e_module.c index 8af6458184..fe55a353f6 100644 --- a/src/bin/e_module.c +++ b/src/bin/e_module.c @@ -1058,6 +1058,7 @@ _e_module_whitelist_check(void) "policy_mobile", "geolocation", "xwayland", + "weather", NULL // end marker }; diff --git a/src/modules/Makefile.mk b/src/modules/Makefile.mk index bb2a65ffe1..1b7573279e 100644 --- a/src/modules/Makefile.mk +++ b/src/modules/Makefile.mk @@ -138,3 +138,5 @@ include src/modules/Makefile_sysinfo.mk include src/modules/Makefile_wireless.mk include src/modules/Makefile_time.mk + +include src/modules/Makefile_weather.mk diff --git a/src/modules/Makefile_weather.mk b/src/modules/Makefile_weather.mk new file mode 100644 index 0000000000..c61c68d4f5 --- /dev/null +++ b/src/modules/Makefile_weather.mk @@ -0,0 +1,29 @@ +EXTRA_DIST += src/modules/weather/module.desktop.in \ +src/modules/weather/e-module-weather.edj + +if USE_MODULE_WEATHER +weatherdir = $(MDIR)/weather +weather_DATA = src/modules/weather/e-module-weather.edj \ + src/modules/weather/module.desktop + + +weatherpkgdir = $(MDIR)/weather/$(MODULE_ARCH) +weatherpkg_LTLIBRARIES = src/modules/weather/module.la + +src_modules_weather_module_la_LIBADD = $(MOD_LIBS) +src_modules_weather_module_la_CPPFLAGS = $(MOD_CPPFLAGS) -DOPENWEATHERMAP_API_KEY=\"@openweathermap_api_key@\" +src_modules_weather_module_la_LDFLAGS = $(MOD_LDFLAGS) +src_modules_weather_module_la_SOURCES = \ +src/modules/weather/config.c \ +src/modules/weather/mod.c \ +src/modules/weather/weather.c \ +src/modules/weather/weather.h \ +src/modules/weather/plugin.c \ +src/modules/weather/plugin.h \ +src/modules/weather/plugin_openweathermap.c \ +src/modules/weather/plugin_openweathermap.h + +PHONIES += weather install-weather +weather: $(weatherpkg_LTLIBRARIES) $(weather_DATA) +install-weather: install-weatherDATA install-weatherpkgLTLIBRARIES +endif diff --git a/src/modules/weather/config.c b/src/modules/weather/config.c new file mode 100644 index 0000000000..302d440dfb --- /dev/null +++ b/src/modules/weather/config.c @@ -0,0 +1,197 @@ +#include "weather.h" +#include "plugin.h" +#include <e.h> + +static Weather *_tmp_weather = NULL; + +static void +_config_label_add(Evas_Object *tb, const char *txt, int row) +{ + Evas_Object *o; + + o = elm_label_add(tb); + E_ALIGN(o, 0, 0.5); + elm_object_text_set(o, txt); + evas_object_show(o); + elm_table_pack(tb, o, 0, row, 1, 1); +} + +static void +_config_close(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + weather_config->config_dialog = NULL; + eina_stringshare_del(_tmp_weather->city); + eina_stringshare_del(_tmp_weather->country); + E_FREE(_tmp_weather); +} + +static void +_config_weather_request(Config_Item *ci) +{ + if (!_tmp_weather) + _tmp_weather = E_NEW(Weather, 1); + eina_stringshare_replace(&_tmp_weather->city, ci->city); + eina_stringshare_replace(&_tmp_weather->country, ci->country); + weather_plugin_request(_tmp_weather); +} + +static void +_config_weather_city_changed(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + const char *city; + Config_Item *ci; + + ci = data; + + city = elm_entry_entry_get(obj); + eina_stringshare_replace(&ci->city, city); + _config_weather_request(ci); +} + +static void +_config_weather_country_changed(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + const char *country; + Config_Item *ci; + + ci = data; + + country = elm_entry_entry_get(obj); + eina_stringshare_replace(&ci->country, country); +} + + +static void +_config_weather_temperature_unit_changed(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Config_Item *ci; + + ci = data; + + ci->use_celcius = elm_check_state_get(obj); +} + +static void +_config_weather_speed_unit_changed(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Config_Item *ci; + + ci = data; + + ci->use_metric = elm_check_state_get(obj); +} + +static void +_config_weather_24h_format_changed(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Config_Item *ci; + + ci = data; + + ci->use_24h = elm_check_state_get(obj); +} + +EINTERN Evas_Object * +config_weather(Config_Item *ci, E_Zone *zone) +{ + Evas_Object *popup, *tb, *fr, *o; + int row = 0; + + if (!zone) zone = e_zone_current_get(); + + popup = elm_popup_add(e_comp->elm); + E_EXPAND(popup); + evas_object_layer_set(popup, E_LAYER_POPUP); + elm_popup_allow_events_set(popup, 1); + elm_popup_scrollable_set(popup, 1); + + tb = elm_table_add(popup); + E_EXPAND(tb); + evas_object_show(tb); + elm_object_content_set(popup, tb); + + _config_label_add(tb, _("City name:"), row++); + + fr = elm_frame_add(tb); + elm_object_style_set(fr, "pad_medium"); + E_FILL(fr); + E_EXPAND(fr); + elm_table_pack(tb, fr, 0, row++, 2, 1); + evas_object_show(fr); + + o = elm_entry_add(tb); + elm_entry_single_line_set(o, EINA_TRUE); + elm_entry_scrollable_set(o, EINA_TRUE); + E_FILL(o); + evas_object_show(o); + elm_object_focus_set(o, EINA_TRUE); + evas_object_smart_callback_add(o, "changed,user", _config_weather_city_changed, ci); + elm_object_part_text_set(o, "guide", _("Your city")); + elm_object_content_set(fr, o); + evas_object_show(o); + + _config_label_add(tb, _("Country name:"), row++); + + fr = elm_frame_add(tb); + elm_object_style_set(fr, "pad_medium"); + E_FILL(fr); + E_EXPAND(fr); + elm_table_pack(tb, fr, 0, row++, 2, 1); + evas_object_show(fr); + + o = elm_entry_add(tb); + elm_entry_single_line_set(o, EINA_TRUE); + elm_entry_scrollable_set(o, EINA_TRUE); + E_FILL(o); + evas_object_show(o); + elm_object_focus_set(o, EINA_TRUE); + evas_object_smart_callback_add(o, "changed,user", _config_weather_country_changed, ci); + elm_object_part_text_set(o, "guide", _("Your country")); + elm_object_content_set(fr, o); + evas_object_show(o); + + + _config_label_add(tb, _("Temperature unit:"), row); + o = elm_check_add(tb); + E_FILL(o); + elm_object_style_set(o, "toggle"); + elm_object_part_text_set(o, "off", _("Farhenheit")); + elm_object_part_text_set(o, "on", _("Celcius")); + elm_table_pack(tb, o, 1, row++, 1, 1); + evas_object_smart_callback_add(o, "changed", _config_weather_temperature_unit_changed, ci); + evas_object_show(o); + + _config_label_add(tb, _("Speed unit:"), row); + o = elm_check_add(tb); + E_FILL(o); + elm_object_style_set(o, "toggle"); + elm_object_part_text_set(o, "off", _("Imperial (mph)")); + elm_object_part_text_set(o, "on", _("Metric (kmh)")); + elm_table_pack(tb, o, 1, row++, 1, 1); + evas_object_smart_callback_add(o, "changed", _config_weather_speed_unit_changed, ci); + evas_object_show(o); + + _config_label_add(tb, _("24 hour format:"), row); + o = elm_check_add(tb); + E_FILL(o); + elm_object_style_set(o, "toggle"); + elm_object_part_text_set(o, "off", _("Disabled")); + elm_object_part_text_set(o, "on", _("Enabled")); + elm_table_pack(tb, o, 1, row++, 1, 1); + evas_object_smart_callback_add(o, "changed", _config_weather_24h_format_changed, ci); + evas_object_show(o); + + + popup = e_comp_object_util_add(popup, E_COMP_OBJECT_TYPE_NONE); + evas_object_layer_set(popup, E_LAYER_POPUP); + evas_object_move(popup, zone->x, zone->y); + evas_object_resize(popup, zone->w / 4, zone->h / 3); + e_comp_object_util_center(popup); + evas_object_show(popup); + e_comp_object_util_autoclose(popup, NULL, e_comp_object_util_autoclose_on_escape, NULL); + evas_object_event_callback_add(popup, EVAS_CALLBACK_DEL, _config_close, NULL); + + return weather_config->config_dialog = popup; +} + + diff --git a/src/modules/weather/e-module-weather.edj b/src/modules/weather/e-module-weather.edj Binary files differnew file mode 100644 index 0000000000..72973357fa --- /dev/null +++ b/src/modules/weather/e-module-weather.edj diff --git a/src/modules/weather/mod.c b/src/modules/weather/mod.c new file mode 100644 index 0000000000..cd7b323e9b --- /dev/null +++ b/src/modules/weather/mod.c @@ -0,0 +1,104 @@ +#include <e.h> +#include "weather.h" +#include "plugin.h" + +static E_Config_DD *conf_edd = NULL; +static E_Config_DD *conf_item_edd = NULL; + +EINTERN void +weather_init(E_Module *m) +{ + conf_item_edd = E_CONFIG_DD_NEW("Config_Item", Config_Item); +#undef T +#undef D +#define T Config_Item +#define D conf_item_edd + E_CONFIG_VAL(D, T, id, INT); + E_CONFIG_VAL(D, T, city, STR); + E_CONFIG_VAL(D, T, country, STR); + E_CONFIG_VAL(D, T, geo_id, STR); + E_CONFIG_VAL(D, T, use_celcius, UCHAR); + E_CONFIG_VAL(D, T, use_metric, UCHAR); + E_CONFIG_VAL(D, T, use_24h, UCHAR); + + conf_edd = E_CONFIG_DD_NEW("Config", Config); +#undef T +#undef D +#define T Config +#define D conf_edd + E_CONFIG_LIST(D, T, items, conf_item_edd); + + weather_config = e_config_domain_load("module.weather", conf_edd); + + if (!weather_config) + weather_config = E_NEW(Config, 1); + weather_plugin_init(); + + weather_config->module = m; + + e_gadget_type_add("Weather small", weather_small_create, weather_small_wizard); + e_gadget_type_add("Weather big", weather_big_create, weather_big_wizard); + +} + +EINTERN void +weather_shutdown(void) +{ + weather_plugin_shutdown(); + if (weather_config) + { + Config_Item *ci; +#if 0 + if (weather_config->config_dialog) + { + evas_object_hide(time_config->config_dialog); + evas_object_del(weather_config->config_dialog); + } +#endif + + EINA_LIST_FREE(weather_config->items, ci) + { + eina_stringshare_del(ci->city); + eina_stringshare_del(ci->country); + eina_stringshare_del(ci->geo_id); + free(ci); + } + + E_FREE(weather_config); + } + E_CONFIG_DD_FREE(conf_edd); + E_CONFIG_DD_FREE(conf_item_edd); + + e_gadget_type_del("Weather small"); + e_gadget_type_del("Weather big"); +} + +/* module setup */ +E_API E_Module_Api e_modapi = +{ + E_MODULE_API_VERSION, + "Weather" +}; + +E_API void * +e_modapi_init(E_Module *m) +{ + if (!E_EFL_VERSION_MINIMUM(1, 17, 99)) return NULL; + weather_init(m); + return m; +} + +E_API int +e_modapi_shutdown(E_Module *m EINA_UNUSED) +{ + weather_shutdown(); + return 1; +} + +E_API int +e_modapi_save(E_Module *m EINA_UNUSED) +{ + e_config_domain_save("module.weather", conf_edd, weather_config); + return 1; +} + diff --git a/src/modules/weather/module.desktop.in b/src/modules/weather/module.desktop.in new file mode 100644 index 0000000000..244cecace9 --- /dev/null +++ b/src/modules/weather/module.desktop.in @@ -0,0 +1,7 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Link +Name=Weather +Comment=Displaying current weather and prevision about it +Icon=e-module-weather +X-Enlightenment-ModuleType=utils diff --git a/src/modules/weather/plugin.c b/src/modules/weather/plugin.c new file mode 100644 index 0000000000..abe6dd8818 --- /dev/null +++ b/src/modules/weather/plugin.c @@ -0,0 +1,234 @@ +#include <e.h> +#include "weather.h" +#include "plugin.h" +#include "plugin_openweathermap.h" + +static Eina_Bool _gather_weather_all(void *data); + +static Eina_List *plugins = NULL; +static Eina_List *weathers = NULL; +static Ecore_Timer *timer = NULL; +static Eina_Binbuf *buffer = NULL; +static Eina_List *handlers = NULL; +static Eina_List *_cur_weather = NULL; +static Eina_List *_cur_plugin = NULL; +static Weather *_cur_request = NULL; + +static void +_gather_current_plugin(void) +{ + Weather_Plugin *wp; + const char *uri; + Ecore_Con_Url *url_con; + Weather *w; + + wp = eina_list_data_get(_cur_plugin); + w = (_cur_request ? _cur_request : eina_list_data_get(_cur_weather)); + fprintf(stderr, "gather info for %s\n", w->city); + if (!w || !wp) return; + uri = wp->func.uri_get(w); + fprintf(stderr, "gather info from %s\n", uri); + url_con = ecore_con_url_new(uri); + ecore_con_url_get(url_con); + eina_stringshare_del(uri); +} + +static Eina_Bool +_gather_weather(void *data EINA_UNUSED) +{ + Weather *w; + timer = NULL; + _cur_plugin = plugins; + w = (_cur_request ? _cur_request : eina_list_data_get(_cur_weather)); + fprintf(stderr, "gather %x data %s %d\n", _cur_weather, w->city, w->translated); + _gather_current_plugin(); + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_gather_weather_all(void *data EINA_UNUSED) +{ + timer = NULL; + fprintf(stderr, "Gather weather data %d %d\n", + eina_list_count(weathers), eina_list_count(plugins)); + _cur_weather = weathers; + _gather_weather(NULL); + + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_url_complete(void *data, int type EINA_UNUSED, void *event EINA_UNUSED) +{ + const unsigned char *buf; + size_t size; + Eina_List *l; + Instance *inst; + Weather_Plugin *wp; + Weather *w; + + if (data != buffer) return ECORE_CALLBACK_PASS_ON; + + buf = eina_binbuf_string_get(buffer); + size = eina_binbuf_length_get(buffer); + + wp = eina_list_data_get(_cur_plugin); + w = (_cur_request ? _cur_request : eina_list_data_get(_cur_weather)); + if (!wp || !w) return ECORE_CALLBACK_DONE; + fprintf(stderr, "gather complete %s %d\n", w->city, w->translated); + wp->func.parse(w, buf, size); + eina_binbuf_reset(buffer); + + EINA_LIST_FOREACH(weather_instances, l, inst) + { + if (inst->weather == w) + weather_gadget_update(inst); + } + _cur_plugin = eina_list_next(_cur_plugin); + if (!_cur_plugin) + { + if (_cur_request) + _cur_request = NULL; + _cur_weather = eina_list_next(_cur_weather); + if (!_cur_weather) + { + if (timer) + ecore_timer_del(timer); + timer = ecore_timer_add(36.0, _gather_weather_all, NULL); + } + else + { + if (timer) + ecore_timer_del(timer); + timer = ecore_timer_add(5.0, _gather_weather, NULL); + } + } + else + { + _gather_current_plugin(); + } + + return ECORE_CALLBACK_DONE; +} + +static Eina_Bool +_url_data(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Url_Data *ev; + + if (data != buffer) return ECORE_CALLBACK_PASS_ON; + ev = event; + + if (ev->size > 0) + { + eina_binbuf_append_length(buffer, ev->data, ev->size); + } + + return ECORE_CALLBACK_DONE; +} + +EINTERN void +weather_plugin_request(Weather *w) +{ + _cur_plugin = plugins; + _cur_request = w; + _gather_weather(NULL); +} + + +EINTERN void +weather_plugin_init(void) +{ + Weather_Plugin *wp; + + buffer = eina_binbuf_new(); + E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_URL_COMPLETE, + _url_complete, buffer); + E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_URL_DATA, + _url_data, buffer); + + wp = plugin_openweathermap_create(); + plugins = eina_list_append(plugins, wp); +} + +EINTERN void +weather_plugin_shutdown(void) +{ + Weather_Plugin *wp; + + EINA_LIST_FREE(plugins, wp) + { + eina_stringshare_del(wp->name); + free(wp); + } + + E_FREE_LIST(handlers, ecore_event_handler_del); + eina_binbuf_free(buffer); +} + +EINTERN void +weather_plugin_weather_add(Instance *inst) +{ + Weather *wl; + Eina_List *l; + + if ((!inst->cfg->city) && (!inst->cfg->country) && (!inst->cfg->geo_id)) + return; + EINA_LIST_FOREACH(weathers, l, wl) + { + if ((inst->cfg->geo_id) && (inst->cfg->geo_id == wl->geo_id)) + break; + if ((inst->cfg->city && inst->cfg->country) + && ((inst->cfg->city == wl->city) + && (inst->cfg->country == wl->country))) + break; + if ((inst->cfg->city) && (inst->cfg->city == wl->city)) + break; + } + if (l) + { + fprintf(stderr, "found weather %s %s %s\n", + inst->weather->geo_id, inst->weather->city, inst->weather->country); + inst->weather = wl; + if (timer) + { + ecore_timer_del(timer); + timer = NULL; + } + timer = ecore_timer_add(1.0, _gather_weather_all, NULL); + + return; + } + fprintf(stderr, "create a new weather %s %s %s\n", + inst->cfg->geo_id, inst->cfg->city, inst->cfg->country); + inst->weather = E_NEW(Weather, 1); + inst->weather->geo_id = eina_stringshare_add(inst->cfg->geo_id); + inst->weather->city = eina_stringshare_add(inst->cfg->city); + inst->weather->country = eina_stringshare_add(inst->cfg->country); + weathers = eina_list_append(weathers, inst->weather); + if (timer) + { + ecore_timer_del(timer); + } + timer = ecore_timer_add(1.0, _gather_weather_all, NULL); +} + +EINTERN void +weather_plugin_weather_remove(Instance *inst) +{ + Instance *inst_search; + Eina_List *l; + + if (!inst->weather) return; + EINA_LIST_FOREACH(weather_instances, l, inst_search) + { + if (inst_search->weather == inst->weather) + break; + } + if (!l) + { + weather_free(inst->weather); + weathers = eina_list_remove(weathers, inst->weather); + } +} + diff --git a/src/modules/weather/plugin.h b/src/modules/weather/plugin.h new file mode 100644 index 0000000000..2906c4200d --- /dev/null +++ b/src/modules/weather/plugin.h @@ -0,0 +1,33 @@ +#ifndef WEATHER_PLUGIN_H +#define WEATHER_PLUGIN_H + +typedef const char *(*Weather_Plugin_Uri) (Weather *wd); +typedef Eina_Bool (*Weather_Plugin_Parse) (Weather *wd, const unsigned char *parse, size_t size); + +typedef enum _Weather_Plugin_Type +{ + WEATHER_PLUGIN_GEOLOC, + WEATHER_PLUGIN_WEATHER_DAY, + WEATHER_PLUGIN_WEATHER_HOUR, +} Weather_Plugin_Type; + +typedef struct _Weather_Plugin +{ + const char *name; + Weather_Plugin_Type type; + Eina_Binbuf *buf; + struct { + Weather_Plugin_Uri uri_get; + Weather_Plugin_Parse parse; + } func; +} Weather_Plugin; + +EINTERN void weather_plugin_init(void); +EINTERN void weather_plugin_shutdown(void); +EINTERN void weather_plugin_weather_add(Instance *inst); +EINTERN void weather_plugin_request(Weather *w); +EINTERN void weather_plugin_weather_remove(Instance *inst); + + + +#endif /* WEATHER_PLUGIN_H */ diff --git a/src/modules/weather/plugin_openweathermap.c b/src/modules/weather/plugin_openweathermap.c new file mode 100644 index 0000000000..cfb7adfb0c --- /dev/null +++ b/src/modules/weather/plugin_openweathermap.c @@ -0,0 +1,540 @@ +#define _GNU_SOURCE 1 +#include <time.h> +#include <e.h> +#include "weather.h" +#include "plugin.h" + + +#define WEATHER_URL "api.openweathermap.org/data/2.5/forecast/" +#define WEATHER_CITY "weather?q=%s" +#define WEATHER_CITY_COUNTRY "weather?q=%s,%s" +#define WEATHER_ID "weather?id=%s" +#define WEATHER_PARAMS "&units=metric&mode=xml" +#define WEATHER_API_KEY "&APPID=" OPENWEATHERMAP_API_KEY + +typedef enum Weather_Tag_ +{ + WEATHER_TAG_NONE = 0, + WEATHER_TAG_CITY = (1 << 0), + WEATHER_TAG_COUNTRY = (1 << 1), + WEATHER_TAG_LOCATION = (1 << 2) +} Weather_Tag; + +static Weather_Tag _xml_tag = 0; +static Weather_Data *_current_wd = NULL; + +static Eina_Bool +_location_attr(void *data, const char *key, const char *value) +{ + Weather *weather; + + weather = data; + + if (!strncmp(key, "altitude", strlen("altitude"))) + weather->altitude = atoi(value); + else if (!strncmp(key, "latitude", strlen("latitude"))) + weather->latitude = atof(value); + else if (!strncmp(key, "longitude", strlen("longitude"))) + weather->longitude = atof(value); + + return EINA_TRUE; + +} + +static Eina_Bool +_sun_attr(void *data, const char *key, const char *value) +{ + Weather *weather; + + weather = data; + + if (!strncmp(key, "rise", strlen("rise"))) + strptime(value, "%Y-%m-%dT%H:%M:%S", &weather->sunrise); + if (!strncmp(key, "set", strlen("set"))) + strptime(value, "%Y-%m-%dT%H:%M:%S", &weather->sunset); + + return EINA_TRUE; +} + +static Eina_Bool +_time_attr(void *data, const char *key, const char *value) +{ + Weather *weather; + Weather_Data *wd = NULL; + struct tm time_start; + Eina_List *l; + + weather = data; + + if (!strncmp(key, "from", strlen("from"))) + { + strptime(value, "%Y-%m-%dT%H:%M:%S", &time_start); + EINA_LIST_FOREACH(weather->datas, l, wd) + { + if ((wd->time_start.tm_hour == time_start.tm_hour) + && (wd->time_start.tm_yday == time_start.tm_yday) + && (wd->time_start.tm_year == time_start.tm_year)) + break; + } + if (!wd) + { + wd = E_NEW(Weather_Data, 1); + memcpy(&wd->time_start, &time_start, sizeof(struct tm)); + weather->datas = eina_list_append(weather->datas, wd); + } + _current_wd = wd; + wd->updated = EINA_TRUE; + } + if (!strncmp(key, "to", strlen("to"))) + strptime(value, "%Y-%m-%dT%H:%M:%S", &_current_wd->time_end); + + + return EINA_TRUE; +} + +static Eina_Bool +_symbol_attr(void *data EINA_UNUSED, const char *key, const char *value) +{ + Weather_Data *wd; + int type; + + wd = _current_wd; + + if (!strncmp(key, "name", strlen("name"))) + eina_stringshare_replace(&wd->state_name, value); + if (!strncmp(key, "number", strlen("number"))) + { + type = atoi(value); + switch (type) + { + case 200: wd->state = WEATHER_STATE_THUNDERSTORM_RAIN_LIGHT; break; + case 201: wd->state = WEATHER_STATE_THUNDERSTORM_RAIN; break; + case 202: wd->state = WEATHER_STATE_THUNDERSTORM_RAIN_HEAVY; break; + case 210: wd->state = WEATHER_STATE_THUNDERSTORM_LIGHT; break; + case 211: wd->state = WEATHER_STATE_THUNDERSTORM; break; + case 212: wd->state = WEATHER_STATE_THUNDERSTORM_HEAVY; break; + case 221: wd->state = WEATHER_STATE_THUNDERSTORM_RAGGED; break; + case 230: wd->state = WEATHER_STATE_THUNDERSTORM_DRIZZLE_LIGHT; break; + case 231: wd->state = WEATHER_STATE_THUNDERSTORM_DRIZZLE; break; + case 232: wd->state = WEATHER_STATE_THUNDERSTORM_DRIZZLE_HEAVY; break; + case 300: wd->state = WEATHER_STATE_DRIZZLE_LIGHT; break; + case 301: wd->state = WEATHER_STATE_DRIZZLE; break; + case 302: wd->state = WEATHER_STATE_DRIZZLE_HEAVY; break; + case 310: wd->state = WEATHER_STATE_DRIZZLE_RAIN_LIGHT; break; + case 311: wd->state = WEATHER_STATE_DRIZZLE_RAIN; break; + case 312: wd->state = WEATHER_STATE_DRIZZLE_RAIN_HEAVY; break; + case 313: wd->state = WEATHER_STATE_DRIZZLE_RAIN_SHOWER; break; + case 314: wd->state = WEATHER_STATE_DRIZZLE_RAIN_SHOWER_HEAVY; break; + case 321: wd->state = WEATHER_STATE_DRIZZLE_SHOWER; break; + case 500: wd->state = WEATHER_STATE_RAIN_LIGHT; break; + case 501: wd->state = WEATHER_STATE_RAIN; break; + case 502: wd->state = WEATHER_STATE_RAIN_HEAVY; break; + case 503: wd->state = WEATHER_STATE_RAIN_VERY_HEAVY; break; + case 504: wd->state = WEATHER_STATE_RAIN_EXTREME; break; + case 511: wd->state = WEATHER_STATE_RAIN_FREEZING; break; + case 520: wd->state = WEATHER_STATE_RAIN_SHOWER_LIGHT; break; + case 521: wd->state = WEATHER_STATE_RAIN_SHOWER; break; + case 522: wd->state = WEATHER_STATE_RAIN_SHOWER_HEAVY; break; + case 531: wd->state = WEATHER_STATE_RAIN_RAGGED; break; + case 600: wd->state = WEATHER_STATE_SNOW_LIGHT; break; + case 601: wd->state = WEATHER_STATE_SNOW; break; + case 602: wd->state = WEATHER_STATE_SNOW_HEAVY; break; + case 611: wd->state = WEATHER_STATE_SLEET; break; + case 612: wd->state = WEATHER_STATE_SLEET_SHOWER; break; + case 615: wd->state = WEATHER_STATE_SNOW_RAIN_LIGHT; break; + case 616: wd->state = WEATHER_STATE_SNOW_RAIN; break; + case 620: wd->state = WEATHER_STATE_SNOW_SHOWER_LIGHT; break; + case 621: wd->state = WEATHER_STATE_SNOW_SHOWER; break; + case 622: wd->state = WEATHER_STATE_SNOW_SHOWER_HEAVY; break; + case 701: wd->state = WEATHER_STATE_MIST; break; + case 711: wd->state = WEATHER_STATE_SMOKE; break; + case 721: wd->state = WEATHER_STATE_HAZE; break; + case 731: wd->state = WEATHER_STATE_DUST_WHIRLS; break; + case 741: wd->state = WEATHER_STATE_FOG; break; + case 751: wd->state = WEATHER_STATE_SAND; break; + case 761: wd->state = WEATHER_STATE_DUST; break; + case 762: wd->state = WEATHER_STATE_VOLCANIC_ASH; break; + case 771: wd->state = WEATHER_STATE_SQUALLS; break; + case 900: + case 781: wd->state = WEATHER_STATE_TORNADO; break; + case 800: wd->state = WEATHER_STATE_CLEAR_SKY; break; + case 801: wd->state = WEATHER_STATE_FEW_CLOUDS; break; + case 802: wd->state = WEATHER_STATE_SCATTERED_CLOUDS; break; + case 803: wd->state = WEATHER_STATE_BROKEN_CLOUDS; break; + case 804: wd->state = WEATHER_STATE_OVERCAST_CLOUDS; break; + case 901: wd->state = WEATHER_STATE_TROPICAL_STORM; break; + case 902: wd->state = WEATHER_STATE_HURRICANE; break; + case 903: wd->state = WEATHER_STATE_COLD; break; + case 904: wd->state = WEATHER_STATE_HOT; break; + case 905: wd->state = WEATHER_STATE_WINDY; break; + case 906: wd->state = WEATHER_STATE_HAIL; break; + } + } + + return EINA_TRUE; +} + +static Eina_Bool +_precipitation_attr(void *data EINA_UNUSED, const char *key, const char *value) +{ + Weather_Data *wd; + + wd = _current_wd; + + if (!strncmp(key, "type", strlen("type"))) + eina_stringshare_replace(&wd->precipitation.type, value); + if (!strncmp(key, "value", strlen("value"))) + wd->precipitation.value = atof(value); + + return EINA_TRUE; +} + +static Eina_Bool +_wind_direction_attr(void *data EINA_UNUSED, const char *key, const char *value) +{ + Weather_Data *wd; + + wd = _current_wd; + + if (!strncmp(key, "deg", strlen("deg"))) + wd->wind.direction_value = atof(value); + else if (!strncmp(key, "code", strlen("code"))) + eina_stringshare_replace(&wd->wind.direction, value); + else if (!strncmp(key, "name", strlen("name"))) + eina_stringshare_replace(&wd->wind.direction_name, value); + + return EINA_TRUE; +} + +static Eina_Bool +_wind_speed_attr(void *data EINA_UNUSED, const char *key, const char *value) +{ + Weather_Data *wd; + + wd = _current_wd; + + if (!strncmp(key, "mps", strlen("mps"))) + wd->wind.speed = atof(value); + else if (!strncmp(key, "name", strlen("name"))) + eina_stringshare_replace(&wd->wind.name, value); + + return EINA_TRUE; +} + +static Eina_Bool +_temperature_attr(void *data EINA_UNUSED, const char *key, const char *value) +{ + Weather_Data *wd; + + wd = _current_wd; + + if (!strncmp(key, "unit", strlen("unit"))) + eina_stringshare_replace(&wd->temperature.unit, value); + else if (!strncmp(key, "value", strlen("value"))) + wd->temperature.value = atof(value); + else if (!strncmp(key, "min", strlen("min"))) + wd->temperature.value_min = atof(value); + else if (!strncmp(key, "max", strlen("max"))) + wd->temperature.value_max = atof(value); + + return EINA_TRUE; +} + +static Eina_Bool +_pressure_attr(void *data EINA_UNUSED, const char *key, const char *value) +{ + Weather_Data *wd; + + wd = _current_wd; + + if (!strncmp(key, "unit", strlen("unit"))) + eina_stringshare_replace(&wd->pressure.unit, value); + else if (!strncmp(key, "value", strlen("value"))) + wd->pressure.value = atof(value); + + return EINA_TRUE; +} + +static Eina_Bool +_humidity_attr(void *data EINA_UNUSED, const char *key, const char *value) +{ + Weather_Data *wd; + + wd = _current_wd; + + if (!strncmp(key, "unit", strlen("unit"))) + eina_stringshare_replace(&wd->humidity.unit, value); + else if (!strncmp(key, "value", strlen("value"))) + wd->humidity.value = atof(value); + + return EINA_TRUE; +} + +static Eina_Bool +_clouds_attr(void *data EINA_UNUSED, const char *key, const char *value) +{ + Weather_Data *wd; + + wd = _current_wd; + + if (!strncmp(key, "unit", strlen("unit"))) + eina_stringshare_replace(&wd->cloud.unit, value); + if (!strncmp(key, "all", strlen("all"))) + wd->cloud.value = atoi(value); + else if (!strncmp(key, "value", strlen("value"))) + eina_stringshare_replace(&wd->cloud.name, value); + + return EINA_TRUE; +} + + +static Eina_Bool +_tag_cb(void *data, Eina_Simple_XML_Type type, const char *content, unsigned int offset EINA_UNUSED, unsigned int length) +{ + char buf[4096]; + const char *tags; + Weather *weather; + + weather = data; + + if (type == EINA_SIMPLE_XML_OPEN) + { + if (!strncmp(content, "name", strlen("name"))) + _xml_tag = WEATHER_TAG_CITY; + else if (!strncmp(content, "country", strlen("country"))) + _xml_tag = WEATHER_TAG_COUNTRY; + else if (!strncmp(content, "location", strlen("location"))) + { + if (weather->plugin_error) weather->plugin_error = EINA_FALSE; + tags = eina_simple_xml_tag_attributes_find(content, length); + eina_simple_xml_attributes_parse(tags, + length - (tags - content), + _location_attr, weather); + } + else if (!strncmp(content, "sun", strlen("sun"))) + { + tags = eina_simple_xml_tag_attributes_find(content, length); + eina_simple_xml_attributes_parse(tags, + length - (tags - content), + _sun_attr, weather); + } + else if (!strncmp(content, "timezone", strlen("timezone"))) + { + } + else if (!strncmp(content, "time", strlen("time"))) + { + tags = eina_simple_xml_tag_attributes_find(content, length); + eina_simple_xml_attributes_parse(tags, + length - (tags - content), + _time_attr, weather); + } + else if (!strncmp(content, "symbol", strlen("symbol"))) + { + tags = eina_simple_xml_tag_attributes_find(content, length); + eina_simple_xml_attributes_parse(tags, + length - (tags - content), + _symbol_attr, weather); + } + else if (!strncmp(content, "precipitation", strlen("precipitation"))) + { + tags = eina_simple_xml_tag_attributes_find(content, length); + eina_simple_xml_attributes_parse(tags, + length - (tags - content), + _precipitation_attr, weather); + } + else if (!strncmp(content, "windDirection", strlen("windDirection"))) + { + tags = eina_simple_xml_tag_attributes_find(content, length); + eina_simple_xml_attributes_parse(tags, + length - (tags - content), + _wind_direction_attr, weather); + } + else if (!strncmp(content, "windSpeed", strlen("windSpeed"))) + { + tags = eina_simple_xml_tag_attributes_find(content, length); + eina_simple_xml_attributes_parse(tags, + length - (tags - content), + _wind_speed_attr, weather); + } + else if (!strncmp(content, "temperature", strlen("temperature"))) + { + tags = eina_simple_xml_tag_attributes_find(content, length); + eina_simple_xml_attributes_parse(tags, + length - (tags - content), + _temperature_attr, weather); + } + else if (!strncmp(content, "pressure", strlen("pressure"))) + { + tags = eina_simple_xml_tag_attributes_find(content, length); + eina_simple_xml_attributes_parse(tags, + length - (tags - content), + _pressure_attr, weather); + } + else if (!strncmp(content, "humidity", strlen("humidity"))) + { + tags = eina_simple_xml_tag_attributes_find(content, length); + eina_simple_xml_attributes_parse(tags, + length - (tags - content), + _humidity_attr, weather); + } + else if (!strncmp(content, "clouds", strlen("clouds"))) + { + tags = eina_simple_xml_tag_attributes_find(content, length); + eina_simple_xml_attributes_parse(tags, + length - (tags - content), + _clouds_attr, weather); + } + } + else if (type == EINA_SIMPLE_XML_DATA) + { + snprintf(buf, length + 1, "%s", content); + // fprintf(stderr, "Type %s\n", buf); + switch (_xml_tag) + { + case WEATHER_TAG_CITY: + if (!weather->city) + eina_stringshare_replace(&weather->city, buf); + break; + case WEATHER_TAG_COUNTRY: + if (!weather->country) + eina_stringshare_replace(&weather->country, buf); + break; + case WEATHER_TAG_LOCATION: + case WEATHER_TAG_NONE: + break; + } + _xml_tag = WEATHER_TAG_NONE; + } + + return EINA_TRUE; +} + +static Eina_Bool +_plugin_openweathermap_parse(Weather *weather, const unsigned char *buf, size_t size) +{ + Weather_Data *wd; + Eina_List *l, *ll; + + printf("%s\n", buf); + + weather->plugin_error = EINA_TRUE; + EINA_LIST_FOREACH(weather->datas, l, wd) + { + wd->updated = EINA_FALSE; + } + eina_simple_xml_parse((const char *)buf, size, EINA_TRUE, _tag_cb, weather); + if (!weather->plugin_error) + { + fprintf(stderr, "Openweather error %s\n", weather->city); + EINA_LIST_FOREACH_SAFE(weather->datas, l, ll, wd) + { + if (!wd->updated) + weather->datas = eina_list_remove_list(weather->datas, l); + } + } + + + +#if 0 + fprintf(stderr, "City %s\nCountry %s\n", weather->city, weather->country); + fprintf(stderr, "Location alt %d geo %.5f %.5f\n", weather->altitude, weather->latitude, weather->longitude); + fprintf(stderr, "Sun %s %s\n", weather->sunrise, weather->sunset); + EINA_LIST_FOREACH(weather->datas, l, wd) + { + fprintf(stderr, "Time %02d:%02d:%02d ", wd->time_start.tm_hour, wd->time_start.tm_min, wd->time_start.tm_sec); +// fprintf(stderr, "Value %s\n", wd->state); + fprintf(stderr, "\t%f min %f max %f unit %s\n", wd->temperature.value, wd->temperature.value_min, wd->temperature.value_max, wd->temperature.unit); + fprintf(stderr, "\t%s %f\n", wd->precipitation.type, wd->precipitation.value); + fprintf(stderr, "\t%s %s %s %f %f\n", wd->wind.name, wd->wind.direction_name, wd->wind.direction, wd->wind.speed); + fprintf(stderr, "\t%s %d %s\n", wd->cloud.name, wd->cloud.value, wd->cloud.unit); + fprintf(stderr, "\t%d %s\n", wd->humidity.value, wd->humidity.unit); + fprintf(stderr, "\t%f %s\n", wd->pressure.value, wd->pressure.unit); + } +#endif + return weather->plugin_error; +} + +static const char * +_plugin_openweathermap_uri_get(Weather *w) +{ + char buf[4096]; + char buf_lang[1024]; + const char *lang; + E_Locale_Parts *lang_part = NULL; + + lang = e_intl_language_get(); + if (lang) + { + lang_part = e_intl_locale_parts_get(lang); + } + + if (lang_part) + { + if ((!strcmp(lang_part->lang, "en")) + || (!strcmp(lang_part->lang, "ru")) + || (!strcmp(lang_part->lang, "it")) + || (!strcmp(lang_part->lang, "es")) + || (!strcmp(lang_part->lang, "uk")) + || (!strcmp(lang_part->lang, "de")) + || (!strcmp(lang_part->lang, "pt")) + || (!strcmp(lang_part->lang, "ro")) + || (!strcmp(lang_part->lang, "pl")) + || (!strcmp(lang_part->lang, "fi")) + || (!strcmp(lang_part->lang, "nl")) + || (!strcmp(lang_part->lang, "fr")) + || (!strcmp(lang_part->lang, "bg")) + || (!strcmp(lang_part->lang, "sv")) + || (!strcmp(lang_part->lang, "zh")) + || (!strcmp(lang_part->lang, "tr")) + || (!strcmp(lang_part->lang, "hr")) + || (!strcmp(lang_part->lang, "ca"))) + { + snprintf(buf_lang, sizeof(buf_lang), "&lang=%s", lang_part->lang); + w->translated = EINA_TRUE; + } + else + *buf_lang = 0; + } + else + *buf_lang = 0; + + if (w->geo_id) + snprintf(buf, sizeof(buf), + WEATHER_URL WEATHER_ID + "%s" + WEATHER_PARAMS WEATHER_API_KEY, + w->geo_id, buf_lang); + else if (w->country && w->city) + snprintf(buf, sizeof(buf), + WEATHER_URL WEATHER_CITY_COUNTRY + "%s" + WEATHER_PARAMS WEATHER_API_KEY, + w->city, w->country, buf_lang); + else if (w->city) + snprintf(buf, sizeof(buf), + WEATHER_URL WEATHER_CITY + "%s" + WEATHER_PARAMS WEATHER_API_KEY, + w->city, buf_lang); + else + *buf = 0; + + if (lang_part) e_intl_locale_parts_free(lang_part); + + return eina_stringshare_add(buf); +} + + +EINTERN Weather_Plugin * +plugin_openweathermap_create(void) +{ + Weather_Plugin *wp; + + wp = E_NEW(Weather_Plugin, 1); + wp->name = eina_stringshare_add("Openweathermap"); + wp->type = WEATHER_PLUGIN_WEATHER_HOUR; + wp->func.uri_get = _plugin_openweathermap_uri_get; + wp->func.parse = _plugin_openweathermap_parse; + + return wp; +} diff --git a/src/modules/weather/plugin_openweathermap.h b/src/modules/weather/plugin_openweathermap.h new file mode 100644 index 0000000000..f07c4ff5f3 --- /dev/null +++ b/src/modules/weather/plugin_openweathermap.h @@ -0,0 +1,6 @@ +#ifndef PLUGIN_OPENWEATHERMAP_H +#define PLUGIN_OPENWEATHERMAP_H + +EINTERN Weather_Plugin *plugin_openweathermap_create(void); + +#endif /* PLUGIN_OPENWEATHERMAP_H */ diff --git a/src/modules/weather/theme.edj b/src/modules/weather/theme.edj Binary files differnew file mode 100644 index 0000000000..895763ecf4 --- /dev/null +++ b/src/modules/weather/theme.edj diff --git a/src/modules/weather/weather.c b/src/modules/weather/weather.c new file mode 100644 index 0000000000..ad925145b2 --- /dev/null +++ b/src/modules/weather/weather.c @@ -0,0 +1,811 @@ +#include "weather.h" +#include "plugin.h" + +EINTERN Config *weather_config = NULL; +EINTERN Eina_List *weather_instances = NULL; + + +typedef enum _Weather_Gadget_Type +{ + WEATHER_GADGET_SMALL, + WEATHER_GADGET_BIG +} Weather_Gadget_Type; + +typedef struct _Wizard_Item +{ + E_Gadget_Wizard_End_Cb cb; + void *data; + int id; +} Wizard_Item; + +typedef struct _Weather_State_Info +{ + Weather_State state; + const char *sig_day_small; + const char *sig_night_small; + const char *sig_day_big; +} Weather_State_Info; + +static void _weather_gadget_removed(void *data, Evas_Object *obj, void *event_info); + +static Evas_Object *_weather_create(Evas_Object *parent, Instance *inst, E_Gadget_Site_Orient orient); +static void _weather_del(void *data, Evas *e, Evas_Object *obj, void *event); +static void _weather_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event); +static void _weather_popup_new(Instance *inst); +static void _weather_popup_day_segment_changed(void *data, Evas_Object *obj, void *event); +static void _weather_popup_day_part_segment_changed(void *data, Evas_Object *obj, void *event); +static void _weather_popup_dismissed(void *data, Evas_Object *obj, void *event); +static void _weather_popup_del(void *data, Evas *e, Evas_Object *obj, void *event_info); +static void _weather_update_object(Instance *inst, Evas_Object *obj, Weather_Data *wd, Eina_Bool big); +static void _weather_wizard(E_Gadget_Wizard_End_Cb cb, void *data); +static void _weather_wizard_end(void *data, Evas *e, Evas_Object *obj, void *event); +static Config_Item *_conf_item_get(int *id); + +static Weather_State_Info _signal_table[] = +{ + { WEATHER_STATE_THUNDERSTORM_RAIN_LIGHT, "thunderstorm", "night_thunderstorm", "right,day_heavyrain,sun,tstorm,rain" }, + { WEATHER_STATE_THUNDERSTORM_RAIN, "thunderstorm", "night_thunderstorm", "right,day_heavyrain,sun,tstorm,rain" }, + { WEATHER_STATE_THUNDERSTORM_RAIN_HEAVY, "thunderstorm", "night_thunderstorm", "right,day_heavyrain,sun,tstorm,rain" }, + { WEATHER_STATE_THUNDERSTORM_LIGHT, "thunderstorm", "night_thunderstorm", "right,day_heavyrain,sun,tstorm,rain" }, + { WEATHER_STATE_THUNDERSTORM, "thunderstorm", "night_thunderstorm", "right,day_heavyrain,sun,tstorm,rain" }, + { WEATHER_STATE_THUNDERSTORM_HEAVY, "thunderstorm", "night_thunderstorm", "right,day_heavyrain,sun,tstorm,rain" }, + { WEATHER_STATE_THUNDERSTORM_RAGGED, "thunderstorm", "night_thunderstorm", "right,day_heavyrain,sun,tstorm,rain" }, + { WEATHER_STATE_THUNDERSTORM_DRIZZLE_LIGHT, "thunderstorm", "night_thunderstorm", "right,day_heavyrain,sun,tstorm,rain" }, + { WEATHER_STATE_THUNDERSTORM_DRIZZLE, "thunderstorm", "night_thunderstorm", "right,day_heavyrain,sun,tstorm,rain" }, + { WEATHER_STATE_THUNDERSTORM_DRIZZLE_HEAVY, "thunderstorm", "night_thunderstorm", "right,day_heavyrain,sun,tstorm,rain" }, + { WEATHER_STATE_DRIZZLE_LIGHT, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_DRIZZLE, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_DRIZZLE_HEAVY, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_DRIZZLE_RAIN_LIGHT, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_DRIZZLE_RAIN, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_DRIZZLE_RAIN_HEAVY, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_DRIZZLE_RAIN_SHOWER, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_DRIZZLE_RAIN_SHOWER_HEAVY, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_DRIZZLE_SHOWER, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_RAIN_LIGHT, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_RAIN, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_RAIN_HEAVY, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_RAIN_VERY_HEAVY, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_RAIN_FREEZING, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_RAIN_SHOWER_LIGHT, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_RAIN_SHOWER, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_RAIN_SHOWER_HEAVY, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_RAIN_RAGGED, "rain", "night_rain", "right,day_rain,sun,rain,rain" }, + { WEATHER_STATE_SNOW_LIGHT, "snow", "night_snow", "right,day_rain,sun,rain,snow" }, + { WEATHER_STATE_SNOW, "snow", "night_snow", "right,day_rain,sun,rain,snow" }, + { WEATHER_STATE_SNOW_HEAVY, "snow", "night_snow", "right,day_rain,sun,rain,snow" }, + { WEATHER_STATE_SLEET, "snow", "night_snow", "right,day_rain,sun,rain,rain_snow" }, + { WEATHER_STATE_SLEET_SHOWER, "snow", "night_snow", "right,day_rain,sun,rain,rain_snow" }, + { WEATHER_STATE_SNOW_RAIN_LIGHT, "snow", "night_snow", "right,day_rain,sun,rain,rain_snow" }, + { WEATHER_STATE_SNOW_RAIN, "snow", "night_snow", "right,day_rain,sun,rain,rain_snow" }, + { WEATHER_STATE_SNOW_SHOWER_LIGHT, "snow", "night_snow", "right,day_rain,sun,rain,rain_snow" }, + { WEATHER_STATE_SNOW_SHOWER, "snow", "night_snow", "right,day_rain,sun,rain,rain_snow" }, + { WEATHER_STATE_SNOW_SHOWER_HEAVY, "snow", "night_snow", "right,day_rain,sun,rain,rain_snow" }, + { WEATHER_STATE_MIST, "mist", "mist", "right,day_rain,sun,cloud,foggy" }, + { WEATHER_STATE_SMOKE, "mist", "mist", "right,day_rain,sun,cloud,foggy" }, + { WEATHER_STATE_HAZE, "mist", "mist", "right,day_rain,sun,cloud,foggy" }, + { WEATHER_STATE_DUST_WHIRLS, "mist", "mist", "right,day_clear,sun,isolated_cloud,windy" }, + { WEATHER_STATE_FOG, "mist", "mist", "right,day_rain,sun,cloud,foggy" }, + { WEATHER_STATE_DUST, "mist", "mist", "right,day_clear,sun,isolated_cloud,windy" }, + { WEATHER_STATE_VOLCANIC_ASH, "mist", "mist", "right,day_clear,sun,isolated_cloud,windy" }, + { WEATHER_STATE_SQUALLS, "mist", "mist", "right,day_clear,sun,isolated_cloud,windy" }, + { WEATHER_STATE_TORNADO, "rain", "night_rain", "right,day_clear,sun,isolated_cloud,windy" }, + { WEATHER_STATE_CLEAR_SKY, "clear", "night_clear", "right,day_clear,sun,nothing," }, + { WEATHER_STATE_FEW_CLOUDS, "few_clouds", "night_few_clouds", "right,day_clear,sun,isolated_cloud," }, + { WEATHER_STATE_SCATTERED_CLOUDS, "scattered_clouds", "night_scattered_clouds", "right,day_clear,sun,cloud," }, + { WEATHER_STATE_BROKEN_CLOUDS, "broken_clouds", "night_broken_clouds", "right,day_clear,sun,cloud," }, + { WEATHER_STATE_OVERCAST_CLOUDS, "broken_clouds", "night_broken_clouds", "right,day_clear,sun,cloud," }, + { WEATHER_STATE_TROPICAL_STORM, "thunderstorm", "night_thunderstorm", "right,day_heavyrain,sun,tstorm,rain" }, + { WEATHER_STATE_HURRICANE, "thunderstorm", "night_thunderstorm", "right,day_heavyrain,sun,tstorm,rain" }, + { WEATHER_STATE_COLD, "clear", "night_clear", "right,day_clear,sun,nothing," }, + { WEATHER_STATE_HOT, "clear", "night_clear", "right,day_clear,sun,nothing," }, + { WEATHER_STATE_WINDY, "clear", "night_clear", "right,day_clear,sun,isolated_cloud,windy" }, + { WEATHER_STATE_HAIL, "clear", "night_clear", "right,day_rain,sun,rain,snow" } +}; + + + +static Config_Item * +_conf_item_get(int *id) +{ + Config_Item *ci; + Eina_List *l; + + if (*id > 0) + { + EINA_LIST_FOREACH(weather_config->items, l, ci) + { + if (ci->id == *id) return ci; + } + } + + ci = E_NEW(Config_Item, 1); + if (!*id) + ci->id = eina_list_count(weather_config->items) + 1; + else + ci->id = -1; + + if (ci->id < 1) return ci; + weather_config->items = eina_list_append(weather_config->items, ci); + e_config_save_queue(); + + return ci; +} + +static void +_weather_gadget_removed(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Instance *inst; + Config_Item *ci; + Eina_List *l; + + inst = data; + evas_object_smart_callback_del_full(inst->obj, "gadget_created", + _weather_gadget_removed, inst); + EINA_LIST_FOREACH(weather_config->items, l, ci) + { + if (ci->id == inst->cfg->id) + { + eina_stringshare_del(ci->geo_id); + eina_stringshare_del(ci->city); + eina_stringshare_del(ci->country); + weather_config->items = + eina_list_remove_list(weather_config->items, l); + break; + } + } +} + +static void +_weather_wizard(E_Gadget_Wizard_End_Cb cb, void *data) +{ + Config_Item *ci; + Wizard_Item *wi; + int id = 0; + + wi = E_NEW(Wizard_Item, 1); + wi->cb = cb; + wi->data = data; + ci = _conf_item_get(&id); + wi->id = ci->id; + evas_object_event_callback_add(config_weather(ci, NULL), EVAS_CALLBACK_DEL, + _weather_wizard_end, wi); +} + +static void +_weather_wizard_end(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) +{ + Wizard_Item *wi; + + wi = data; + + wi->cb(wi->data, wi->id); + free(wi); +} + +static Evas_Object * +_weather_create(Evas_Object *parent, Instance *inst, E_Gadget_Site_Orient orient EINA_UNUSED) +{ + Evas_Object *o; + char buf[PATH_MAX]; + + + o = elm_layout_add(parent); + inst->obj = o; + snprintf(buf, sizeof(buf), "%s/e-module-weather.edj", e_module_dir_get(weather_config->module)); + elm_layout_file_set(o, buf, "e/gadget/weather/small"); + evas_object_size_hint_aspect_set(o, EVAS_ASPECT_CONTROL_BOTH, 1.0, 1.0); + evas_object_size_hint_min_set(o, 32, 32); + evas_object_size_hint_max_set(o, 32, 32); + + evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _weather_del, inst); + evas_object_smart_callback_add(o, "gadget_removed", + _weather_gadget_removed, inst); + evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, + _weather_mouse_down, inst); + + weather_instances = eina_list_append(weather_instances, inst); + weather_plugin_weather_add(inst); + + return o; +} + +static void +_weather_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) +{ + Instance *inst; + + inst = data; + + weather_instances = eina_list_remove(weather_instances, inst); + weather_plugin_weather_remove(inst); + free(inst); +} + +static void +_weather_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event) +{ + Instance *inst; + Evas_Event_Mouse_Down *ev; + + inst = data; + ev = event; + + if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; + ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; + if (ev->button == 1) + { + if (inst->popup) elm_ctxpopup_dismiss(inst->popup); + else _weather_popup_new(inst); + } +} + +static void +_weather_popup_new(Instance *inst) +{ + Evas_Object *o; + Evas_Object *vbx; + Evas_Object *seg; + Eina_List *l; + Weather_Data *wd; + char buf[4096]; + int last_day = -1; + Elm_Object_Item *it; + time_t tt; + const struct tm *now; + + tt = time(NULL); + now = localtime(&tt); + + if (inst->popup) return; + if (!inst->weather) return; + inst->popup = elm_ctxpopup_add(inst->obj); + elm_object_style_set(inst->popup, "noblock"); + + evas_object_smart_callback_add(inst->popup, "dismissed", _weather_popup_dismissed, inst); + evas_object_event_callback_add(inst->popup, EVAS_CALLBACK_DEL, _weather_popup_del, inst); + + vbx = elm_box_add(inst->popup); + elm_box_horizontal_set(vbx, EINA_FALSE); + seg = elm_segment_control_add(vbx); + evas_object_size_hint_weight_set(seg, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(seg, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_min_set(seg, 320, 0); + EINA_LIST_FOREACH(inst->weather->datas, l, wd) + { + if (last_day != wd->time_start.tm_mday) + { + last_day = wd->time_start.tm_mday; + if (now->tm_mday == wd->time_start.tm_mday) + snprintf(buf, sizeof(buf), _("Today")); + else + strftime(buf, sizeof(buf), "%A", &wd->time_start); + it = elm_segment_control_item_add(seg, NULL, buf); + elm_object_item_data_set(it, wd); + } + } + evas_object_smart_callback_add(seg, "changed", + _weather_popup_day_segment_changed, inst); + it = elm_segment_control_item_get(seg, 0); + elm_box_pack_end(vbx, seg); + evas_object_show(seg); + + seg = elm_segment_control_add(vbx); + inst->popup_segment = seg; + evas_object_size_hint_weight_set(seg, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(seg, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(vbx, seg); + evas_object_smart_callback_add(seg, "changed", + _weather_popup_day_part_segment_changed, inst); + evas_object_show(seg); + + o = elm_layout_add(vbx); + inst->popup_weather = o; + evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); + snprintf(buf, sizeof(buf), "%s/e-module-weather.edj", + e_module_dir_get(weather_config->module)); + elm_layout_file_set(o, buf, "e/gadget/weather/big"); + elm_box_pack_end(vbx, o); + evas_object_show(o); + evas_object_show(vbx); + evas_object_size_hint_min_set(inst->popup, 0, 360); + elm_object_content_set(inst->popup, vbx); + e_gadget_util_ctxpopup_place(inst->obj, inst->popup, NULL); + evas_object_show(inst->popup); + + if (it) + elm_segment_control_item_selected_set(it, EINA_TRUE); +} + + +static void +_weather_format_time(char *buf, size_t size, const struct tm *tm, Eina_Bool use_24h) +{ + if (!use_24h) + { + if (tm->tm_hour > 12) + { + snprintf(buf, size, "%d PM", (tm->tm_hour - 12)); + } + else + { + if (tm->tm_hour != 0) + snprintf(buf, size, "%d AM", tm->tm_hour); + else + snprintf(buf, size, "12 PM"); + } + } + else + strftime(buf, size, "%H h", tm); +} + +static void +_weather_popup_day_segment_changed(void *data, Evas_Object *obj EINA_UNUSED, void *event) +{ + Elm_Object_Item *it; + Instance *inst; + Weather_Data *wd, *it_wd; + Eina_List *l; + int idx; + char buf[4096]; + + it = event; + inst = data; + it_wd = elm_object_item_data_get(it); + + idx = elm_segment_control_item_count_get(inst->popup_segment); + for (--idx; idx >= 0; --idx) + { + elm_segment_control_item_del_at(inst->popup_segment, idx); + } + + + EINA_LIST_FOREACH(inst->weather->datas, l, wd) + { + if ((((wd->time_start.tm_mday == it_wd->time_start.tm_mday) + && (wd->time_start.tm_hour != 0))) + || ((wd->time_start.tm_mday == (it_wd->time_start.tm_mday + 1) + && (wd->time_start.tm_hour == 0)))) + { + _weather_format_time(buf, sizeof(buf), + &wd->time_start, inst->cfg->use_24h); + it = elm_segment_control_item_add(inst->popup_segment, NULL, buf); + elm_object_item_data_set(it, wd); + } + } + it = elm_segment_control_item_get(inst->popup_segment, 0); + if (it) + elm_segment_control_item_selected_set(it, EINA_TRUE); +} + +static void +_weather_popup_day_part_segment_changed(void *data, Evas_Object *obj EINA_UNUSED, void *event) +{ + Elm_Object_Item *it; + Instance *inst; + Weather_Data *wd; + + it = event; + inst = data; + wd = elm_object_item_data_get(it); + + _weather_update_object(inst, inst->popup_weather, wd, EINA_TRUE); +} + +static void +_weather_popup_dismissed(void *data EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED) +{ + evas_object_del(obj); +} + + +static void +_weather_popup_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Instance *inst; + + inst = data; + + inst->popup = NULL; + inst->popup_segment = NULL; + inst->popup_weather = NULL; +} + +static double +_weather_convert_celcius_to_farhenheit(double celcius) +{ + return ((celcius * 9.) / 5.) + 32.; +} + + +static void +_weather_update_object(Instance *inst, Evas_Object *obj, Weather_Data *wd, Eina_Bool big) +{ + Eina_Bool night = EINA_FALSE; + const char *condition = ""; + char buf[4096]; + char buf_time[4096]; + char buf_time2[4096]; + unsigned int i; + time_t tt; + const struct tm *now; + + + if (wd->time_start.tm_hour <= inst->weather->sunrise.tm_hour) + { + night = EINA_TRUE; + } + else if (wd->time_start.tm_hour >= inst->weather->sunset.tm_hour) + { + night = EINA_TRUE; + } + + + + if (!inst->weather->translated) + { + switch (wd->state) + { + case WEATHER_STATE_THUNDERSTORM_RAIN_LIGHT: + condition = _("thunderstorm with light rain"); + break; + case WEATHER_STATE_THUNDERSTORM_RAIN: + condition = _("thunderstorm with rain"); + break; + case WEATHER_STATE_THUNDERSTORM_RAIN_HEAVY: + condition = _("thunderstorm with heavy rain"); + break; + case WEATHER_STATE_THUNDERSTORM_LIGHT: + condition = _("light thunderstorm"); + break; + case WEATHER_STATE_THUNDERSTORM: + condition = _("Thunderstorm"); + break; + case WEATHER_STATE_THUNDERSTORM_HEAVY: + condition = _("Heavy thunderstorm"); + break; + case WEATHER_STATE_THUNDERSTORM_RAGGED: + condition = _("Ragged thunderstorm"); + break; + case WEATHER_STATE_THUNDERSTORM_DRIZZLE_LIGHT: + condition = _("Thunderstorm with light drizzle"); + break; + case WEATHER_STATE_THUNDERSTORM_DRIZZLE: + condition = _("Thunderstorm with drizzle"); + break; + case WEATHER_STATE_THUNDERSTORM_DRIZZLE_HEAVY: + condition = _("Thunderstorm with heavy drizzle"); + break; + case WEATHER_STATE_DRIZZLE_LIGHT: + condition = _("Light drizzle"); + break; + case WEATHER_STATE_DRIZZLE: + condition = _("Drizzle"); + break; + case WEATHER_STATE_DRIZZLE_HEAVY: + condition = _("Heavy drizzle"); + break; + case WEATHER_STATE_DRIZZLE_RAIN_LIGHT: + condition = _("Drizzle with light rain"); + break; + case WEATHER_STATE_DRIZZLE_RAIN: + condition = _("Drizzle with rain"); + break; + case WEATHER_STATE_DRIZZLE_RAIN_HEAVY: + condition = _("Drizzle with heavy rain"); + break; + case WEATHER_STATE_DRIZZLE_RAIN_SHOWER: + condition = _("Drizzle with shower rain"); + break; + case WEATHER_STATE_DRIZZLE_RAIN_SHOWER_HEAVY: + condition = _("Drizzle with heavy shower rain"); + break; + case WEATHER_STATE_DRIZZLE_SHOWER: + condition = _("Shower drizzle"); + break; + case WEATHER_STATE_RAIN_LIGHT: + condition = _("Light rain"); + break; + case WEATHER_STATE_RAIN: + condition = _("Rain"); + break; + case WEATHER_STATE_RAIN_HEAVY: + condition = _("Heavy rain"); + break; + case WEATHER_STATE_RAIN_VERY_HEAVY: + condition = _("Very heavy rain"); + break; + case WEATHER_STATE_RAIN_EXTREME: + condition = _("Extreme rain"); + break; + case WEATHER_STATE_RAIN_FREEZING: + condition = _("Freezing rain"); + break; + case WEATHER_STATE_RAIN_SHOWER_LIGHT: + condition = _("Light shower rain"); + break; + case WEATHER_STATE_RAIN_SHOWER: + condition = _("Shower rain"); + break; + case WEATHER_STATE_RAIN_SHOWER_HEAVY: + condition = _("Heavy shower rain"); + break; + case WEATHER_STATE_RAIN_RAGGED: + condition = _("Ragged rain"); + break; + case WEATHER_STATE_SNOW_LIGHT: + condition = _("Light snow"); + break; + case WEATHER_STATE_SNOW: + condition = _("Snow"); + break; + case WEATHER_STATE_SNOW_HEAVY: + condition = _("Heavy snow"); + break; + case WEATHER_STATE_SLEET: + condition = _("Sleet"); + break; + case WEATHER_STATE_SLEET_SHOWER: + condition = _("Shower sleet"); + break; + case WEATHER_STATE_SNOW_RAIN_LIGHT: + condition = _("Snow with light rain"); + break; + case WEATHER_STATE_SNOW_RAIN: + condition = _("Snow with rain"); + break; + case WEATHER_STATE_SNOW_SHOWER_LIGHT: + condition = _("Light shower snow"); + break; + case WEATHER_STATE_SNOW_SHOWER: + condition = _("Shower snow"); + break; + case WEATHER_STATE_SNOW_SHOWER_HEAVY: + condition = _("Heavy shower snow"); + break; + case WEATHER_STATE_MIST: + condition = _("Mist"); + break; + case WEATHER_STATE_SMOKE: + condition = _("Smoke"); + break; + case WEATHER_STATE_HAZE: + condition = _("Haze"); + break; + case WEATHER_STATE_DUST_WHIRLS: + condition = _("Sand, dust whirls"); + break; + case WEATHER_STATE_FOG: + condition = _("Fog"); + break; + case WEATHER_STATE_SAND: + condition = _("Sand"); + break; + case WEATHER_STATE_DUST: + condition = _("Dust"); + break; + case WEATHER_STATE_VOLCANIC_ASH: + condition = _("Volcanic ash"); + break; + case WEATHER_STATE_SQUALLS: + condition = _("Squalls"); + break; + case WEATHER_STATE_TORNADO: + condition = _("Tornado"); + break; + case WEATHER_STATE_CLEAR_SKY: + condition = _("Clear"); + break; + case WEATHER_STATE_FEW_CLOUDS: + condition = _("Few clouds"); + break; + case WEATHER_STATE_SCATTERED_CLOUDS: + condition = _("Scattered clouds"); + break; + case WEATHER_STATE_BROKEN_CLOUDS: + condition = _("Broken clouds"); + break; + case WEATHER_STATE_OVERCAST_CLOUDS: + condition = _("Overcast clouds"); + break; + case WEATHER_STATE_TROPICAL_STORM: + condition = _("Tropical storm"); + break; + case WEATHER_STATE_HURRICANE: + condition = _("Hurricane"); + break; + case WEATHER_STATE_COLD: + condition = _("Cold"); + break; + case WEATHER_STATE_HOT: + condition = _("Hot"); + break; + case WEATHER_STATE_WINDY: + condition = _("Windy"); + break; + case WEATHER_STATE_HAIL: + condition = _("Hail"); + break; + } + elm_object_part_text_set(obj, "text.condition", condition); + } + else + elm_object_part_text_set(obj, "text.condition", wd->state_name); + + if (inst->cfg->use_celcius) + snprintf(buf, sizeof(buf), "%01.1f °C", wd->temperature.value); + else + snprintf(buf, sizeof(buf), "%01.1f °F", + _weather_convert_celcius_to_farhenheit(wd->temperature.value)); + elm_object_part_text_set(obj, "text.temp", buf); + + if (big) + { + _weather_format_time(buf_time, sizeof(buf_time), + &wd->time_start, inst->cfg->use_24h); + _weather_format_time(buf_time2, sizeof(buf_time2), + &wd->time_end, inst->cfg->use_24h); + snprintf(buf, sizeof(buf), "%s - %s", buf_time, buf_time2); + elm_object_part_text_set(obj, "text.date", buf); + snprintf(buf, sizeof(buf), "%s (%s)", + inst->weather->city, inst->weather->country); + elm_object_part_text_set(obj, "text.city", buf); + tt = time(NULL); + now = localtime(&tt); + if (now->tm_mday == wd->time_start.tm_mday) + { + strftime(buf_time, sizeof(buf_time), "%X", &inst->weather->sunrise); + snprintf(buf, sizeof(buf), _("sunrise %s"), buf_time); + elm_object_part_text_set(obj, "text.sunrise", buf); + strftime(buf_time, sizeof(buf_time), "%X", &inst->weather->sunset); + snprintf(buf, sizeof(buf), _("Sunset %s"), buf_time); + elm_object_part_text_set(obj, "text.sunrise", buf); + } + if (inst->cfg->use_celcius) + snprintf(buf, sizeof(buf), "%01.1f °C", wd->temperature.value_min); + else + snprintf(buf, sizeof(buf), "%01.1f °F", + _weather_convert_celcius_to_farhenheit(wd->temperature.value_min)); + elm_object_part_text_set(obj, "text.temp_min", buf); + if (inst->cfg->use_celcius) + snprintf(buf, sizeof(buf), "%01.1f °C", wd->temperature.value_max); + else + snprintf(buf, sizeof(buf), "%01.1f °F", + _weather_convert_celcius_to_farhenheit(wd->temperature.value_max)); + elm_object_part_text_set(obj, "text.temp_max", buf); + snprintf(buf, sizeof(buf), _("Wind : %s"), wd->wind.name); + elm_object_part_text_set(obj, "text.wind", buf); + if (inst->cfg->use_metric) + snprintf(buf, sizeof(buf), _("Speed : %01.1f Kmh"), (wd->wind.speed * 3.6)); + else + snprintf(buf, sizeof(buf), _("Speed : %01.1f Mph"), (wd->wind.speed * 2.2369)); + elm_object_part_text_set(obj, "text.wind_speed", buf); + snprintf(buf, sizeof(buf), _("Direction : %s"), wd->wind.direction); + elm_object_part_text_set(obj, "text.wind_direction", buf); + snprintf(buf, sizeof(buf), _("Pressure : %01.1f %s"), wd->pressure.value, wd->pressure.unit); + elm_object_part_text_set(obj, "text.pressure", buf); + snprintf(buf, sizeof(buf), _("Humidity : %01d %s"), wd->humidity.value, wd->humidity.unit); + elm_object_part_text_set(obj, "text.humidity", buf); + snprintf(buf, sizeof(buf), _("Precipitation : %01.2f mm"), wd->precipitation.value); + elm_object_part_text_set(obj, "text.precipitation", buf); + snprintf(buf, sizeof(buf), _("Cloud : %01d %s"), wd->cloud.value, wd->cloud.unit); + elm_object_part_text_set(obj, "text.cloud", buf); + } + + for (i = 0; i < (sizeof(_signal_table) / sizeof(_signal_table[0])); ++i) + { + if (_signal_table[i].state == wd->state) + { + if (night) + { + if (big) + elm_object_signal_emit(obj, _signal_table[i].sig_day_big, ""); + else + elm_object_signal_emit(obj, _signal_table[i].sig_night_small, ""); + } + else + { + if (big) + elm_object_signal_emit(obj, _signal_table[i].sig_day_big, ""); + else + elm_object_signal_emit(obj, _signal_table[i].sig_day_small, ""); + } + break; + } + } + +} + +EINTERN void +weather_gadget_update(Instance *inst) +{ + Eina_Bool cfg_update = EINA_FALSE; + Weather_Data *wd; + + if (inst->cfg->city != inst->weather->city) + { + eina_stringshare_replace(&inst->cfg->city, inst->weather->city); + cfg_update = EINA_TRUE; + } + if (inst->cfg->country != inst->weather->country) + { + eina_stringshare_replace(&inst->cfg->country, inst->weather->country); + cfg_update = EINA_TRUE; + } + if (inst->cfg->geo_id != inst->weather->geo_id) + { + eina_stringshare_replace(&inst->cfg->geo_id, inst->weather->geo_id); + cfg_update = EINA_TRUE; + } + if (cfg_update) e_config_save_queue(); + if (inst->obj) + { + wd = eina_list_data_get(inst->weather->datas); + if (!wd) return; + fprintf(stderr, "updating gadget\n"); + _weather_update_object(inst, inst->obj, wd, EINA_FALSE); + } +} + +EINTERN Evas_Object * +weather_small_create(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient) +{ + Instance *inst; + + inst = E_NEW(Instance, 1); + inst->cfg = _conf_item_get(id); + return _weather_create(parent, inst, orient); +} + +EINTERN Evas_Object * +weather_big_create(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient) +{ + Instance *inst; + + inst = E_NEW(Instance, 1); + inst->cfg = _conf_item_get(id); + return _weather_create(parent, inst, orient); +} + +EINTERN void +weather_small_wizard(E_Gadget_Wizard_End_Cb cb, void *data) +{ + _weather_wizard(cb, data); +} + + +EINTERN void +weather_big_wizard(E_Gadget_Wizard_End_Cb cb, void *data) +{ + _weather_wizard(cb, data); +} + +EINTERN void +weather_data_free(Weather_Data *wd) +{ + eina_stringshare_del(wd->state_name); + eina_stringshare_del(wd->temperature.unit); + eina_stringshare_del(wd->precipitation.type); + eina_stringshare_del(wd->wind.name); + eina_stringshare_del(wd->wind.direction_name); + eina_stringshare_del(wd->wind.direction); + eina_stringshare_del(wd->cloud.name); + eina_stringshare_del(wd->cloud.unit); + eina_stringshare_del(wd->humidity.unit); + eina_stringshare_del(wd->pressure.unit); + free(wd); +} + +EINTERN void +weather_free(Weather *weather) +{ + Weather_Data *wd; + + eina_stringshare_del(weather->city); + eina_stringshare_del(weather->country); + eina_stringshare_del(weather->geo_id); + EINA_LIST_FREE(weather->datas, wd) + weather_data_free(wd); + free(weather); +} diff --git a/src/modules/weather/weather.h b/src/modules/weather/weather.h new file mode 100644 index 0000000000..a300cfb35e --- /dev/null +++ b/src/modules/weather/weather.h @@ -0,0 +1,190 @@ +#ifndef WEATHER_H +#define WEATHER_H + +#include "e.h" + +E_API extern E_Module_Api e_modapi; + +E_API void *e_modapi_init (E_Module *m); +E_API int e_modapi_shutdown (E_Module *m); +E_API int e_modapi_save (E_Module *m); + +typedef struct _Config Config; +typedef struct _Config_Item Config_Item; +typedef struct _Instance Instance; + +typedef enum _Weather_State +{ + WEATHER_STATE_CLEAR_SKY, + WEATHER_STATE_FEW_CLOUDS, + WEATHER_STATE_SCATTERED_CLOUDS, + WEATHER_STATE_BROKEN_CLOUDS, + WEATHER_STATE_OVERCAST_CLOUDS, + WEATHER_STATE_THUNDERSTORM_LIGHT, + WEATHER_STATE_THUNDERSTORM, + WEATHER_STATE_THUNDERSTORM_RAIN_LIGHT, + WEATHER_STATE_THUNDERSTORM_RAIN, + WEATHER_STATE_THUNDERSTORM_RAIN_HEAVY, + WEATHER_STATE_THUNDERSTORM_HEAVY, + WEATHER_STATE_THUNDERSTORM_RAGGED, + WEATHER_STATE_THUNDERSTORM_DRIZZLE_LIGHT, + WEATHER_STATE_THUNDERSTORM_DRIZZLE, + WEATHER_STATE_THUNDERSTORM_DRIZZLE_HEAVY, + WEATHER_STATE_DRIZZLE_LIGHT, + WEATHER_STATE_DRIZZLE, + WEATHER_STATE_DRIZZLE_HEAVY, + WEATHER_STATE_DRIZZLE_RAIN_LIGHT, + WEATHER_STATE_DRIZZLE_RAIN, + WEATHER_STATE_DRIZZLE_RAIN_HEAVY, + WEATHER_STATE_DRIZZLE_RAIN_SHOWER, + WEATHER_STATE_DRIZZLE_RAIN_SHOWER_HEAVY, + WEATHER_STATE_DRIZZLE_SHOWER, + WEATHER_STATE_RAIN_LIGHT, + WEATHER_STATE_RAIN, + WEATHER_STATE_RAIN_HEAVY, + WEATHER_STATE_RAIN_VERY_HEAVY, + WEATHER_STATE_RAIN_EXTREME, + WEATHER_STATE_RAIN_FREEZING, + WEATHER_STATE_RAIN_SHOWER_LIGHT, + WEATHER_STATE_RAIN_SHOWER, + WEATHER_STATE_RAIN_SHOWER_HEAVY, + WEATHER_STATE_RAIN_RAGGED, + WEATHER_STATE_SNOW_LIGHT, + WEATHER_STATE_SNOW, + WEATHER_STATE_SNOW_HEAVY, + WEATHER_STATE_SLEET, + WEATHER_STATE_SLEET_SHOWER, + WEATHER_STATE_SNOW_RAIN_LIGHT, + WEATHER_STATE_SNOW_RAIN, + WEATHER_STATE_SNOW_SHOWER_LIGHT, + WEATHER_STATE_SNOW_SHOWER, + WEATHER_STATE_SNOW_SHOWER_HEAVY, + WEATHER_STATE_MIST, + WEATHER_STATE_SMOKE, + WEATHER_STATE_HAZE, + WEATHER_STATE_DUST_WHIRLS, + WEATHER_STATE_FOG, + WEATHER_STATE_SAND, + WEATHER_STATE_DUST, + WEATHER_STATE_VOLCANIC_ASH, + WEATHER_STATE_SQUALLS, + WEATHER_STATE_TORNADO, + WEATHER_STATE_TROPICAL_STORM, + WEATHER_STATE_HURRICANE, + WEATHER_STATE_COLD, + WEATHER_STATE_HOT, + WEATHER_STATE_WINDY, + WEATHER_STATE_HAIL, +} Weather_State; + +struct _Config +{ + Eina_List *items; + + E_Module *module; + Evas_Object *config_dialog; +}; + +struct _Config_Item +{ + int id; + const char *geo_id; + const char *city; + const char *country; + unsigned char use_celcius; + unsigned char use_metric; + unsigned char use_24h; +}; + + +typedef struct Weather_ +{ + const char *city; + const char *country; + const char *geo_id; + int altitude; + double latitude; + double longitude; + struct tm sunrise; + struct tm sunset; + Eina_List *datas; +// Config_Item *cfg; + Eina_Bool translated; + Eina_Bool plugin_error; +} Weather; + +typedef struct Weather_Data_ +{ + struct tm time_start; + struct tm time_end; + Weather_State state; + const char *state_name; + struct + { + double value; + double value_min; + double value_max; + const char *unit; + } temperature; + struct + { + const char *type; + double value; + } precipitation; + struct + { + const char *name; + const char *direction_name; + const char *direction; + double direction_value; + double speed; + } wind; + struct + { + const char *name; + int value; + const char *unit; + } cloud; + struct + { + int value; + const char *unit; + } humidity; + struct + { + double value; + const char *unit; + } pressure; + Eina_Bool updated; +} Weather_Data; + +struct _Instance +{ + Evas_Object *obj; + Evas_Object *popup; + Evas_Object *popup_segment; + Evas_Object *popup_weather; + Config_Item *cfg; + Weather *weather; +}; + + +EINTERN Evas_Object *config_weather(Config_Item *, E_Zone*); + +EINTERN void weather_init(E_Module *m); +EINTERN void weather_shutdown(void); + +EINTERN Evas_Object *weather_small_create(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient); +EINTERN Evas_Object *weather_big_create(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient); +EINTERN void weather_small_wizard(E_Gadget_Wizard_End_Cb cb, void *data); +EINTERN void weather_big_wizard(E_Gadget_Wizard_End_Cb cb, void *data); +EINTERN void weather_gadget_update(Instance *inst); + +EINTERN void weather_free(Weather *weather); +EINTERN void weather_data_free(Weather_Data *wd); + +extern Config *weather_config; +extern Eina_List *weather_instances; +extern Eina_List *weather_list; + +#endif |