/* TODO: config dialog to select which modem to monitor */ #include "e.h" #include "e_mod_main.h" static E_Module *ofono_mod = NULL; static char tmpbuf[PATH_MAX]; const char _e_ofono_name[] = "ofono"; const char _e_ofono_Name[] = N_("Mobile Modems Info"); int _e_ofono_module_log_dom = -1; static void _ofono_gadget_update(E_Ofono_Instance *inst); static void _ofono_tip_update(E_Ofono_Instance *inst); const char * e_ofono_theme_path(void) { #define TF "/e-module-ofono.edj" size_t dirlen; dirlen = strlen(ofono_mod->dir); if (dirlen >= sizeof(tmpbuf) - sizeof(TF)) return NULL; memcpy(tmpbuf, ofono_mod->dir, dirlen); memcpy(tmpbuf + dirlen, TF, sizeof(TF)); return tmpbuf; #undef TF } static void _ofono_popup_del(E_Ofono_Instance *inst); static Eina_Bool _ofono_popup_input_window_mouse_up_cb(void *data, int type __UNUSED__, void *event) { Ecore_Event_Mouse_Button *ev = event; E_Ofono_Instance *inst = data; if (ev->window != inst->ui.input.win) return ECORE_CALLBACK_PASS_ON; _ofono_popup_del(inst); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _ofono_popup_input_window_key_down_cb(void *data, int type __UNUSED__, void *event) { Ecore_Event_Key *ev = event; E_Ofono_Instance *inst = data; const char *keysym; if (ev->window != inst->ui.input.win) return ECORE_CALLBACK_PASS_ON; keysym = ev->key; if (!strcmp(keysym, "Escape")) _ofono_popup_del(inst); return ECORE_CALLBACK_PASS_ON; } static void _ofono_popup_input_window_destroy(E_Ofono_Instance *inst) { ecore_x_window_free(inst->ui.input.win); inst->ui.input.win = 0; ecore_event_handler_del(inst->ui.input.mouse_up); inst->ui.input.mouse_up = NULL; ecore_event_handler_del(inst->ui.input.key_down); inst->ui.input.key_down = NULL; } static void _ofono_popup_input_window_create(E_Ofono_Instance *inst) { Ecore_X_Window_Configure_Mask mask; Ecore_X_Window w, popup_w; E_Manager *man; man = e_manager_current_get(); w = ecore_x_window_input_new(man->root, 0, 0, man->w, man->h); mask = (ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE | ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING); popup_w = inst->popup->win->evas_win; ecore_x_window_configure(w, mask, 0, 0, 0, 0, 0, popup_w, ECORE_X_WINDOW_STACK_BELOW); ecore_x_window_show(w); inst->ui.input.mouse_up = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, _ofono_popup_input_window_mouse_up_cb, inst); inst->ui.input.key_down = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _ofono_popup_input_window_key_down_cb, inst); inst->ui.input.win = w; } static void _ofono_toggle_powered_cb(void *data, DBusMessage *msg __UNUSED__, DBusError *error) { E_Ofono_Instance *inst = data; if ((error) && (dbus_error_is_set(error))) _ofono_dbus_error_show(_("Failed to power modem on/off."), error); else DBG("new powered value set"); e_widget_disabled_set(inst->ui.powered, (int)EINA_FALSE); inst->powered_pending = EINA_FALSE; dbus_error_free(error); } static void _ofono_popup_cb_powered_changed(void *data, Evas_Object *obj, void *event __UNUSED__) { E_Ofono_Instance *inst = data; E_Ofono_Module_Context *ctxt = inst->ctxt; Eina_Bool powered = e_widget_check_checked_get(obj); if ((!ctxt) || (!ctxt->has_manager)) { _ofono_operation_error_show(_("oFono Daemon is not running.")); return; } if (!e_ofono_modem_powered_set(inst->modem_element, powered, _ofono_toggle_powered_cb, inst)) { _ofono_operation_error_show(_("Cannot toggle modem's powered state.")); return; } e_widget_disabled_set(obj, EINA_TRUE); inst->powered_pending = EINA_TRUE; DBG("powered = %d pending", !inst->powered); } static void _ofono_popup_update(E_Ofono_Instance *inst) { if (inst->name) e_widget_label_text_set(inst->ui.name, inst->name); else e_widget_label_text_set(inst->ui.name, _("No modem available")); e_widget_check_checked_set(inst->ui.powered, inst->powered); } static void _ofono_popup_del(E_Ofono_Instance *inst) { _ofono_popup_input_window_destroy(inst); e_object_del(E_OBJECT(inst->popup)); inst->popup = NULL; } static void _ofono_popup_new(E_Ofono_Instance *inst) { Evas *evas; Evas_Coord mw, mh; if (inst->popup) { e_gadcon_popup_show(inst->popup); return; } inst->popup = e_gadcon_popup_new(inst->gcc); evas = inst->popup->win->evas; inst->ui.table = e_widget_table_add(evas, 0); if (inst->name) inst->ui.name = e_widget_label_add(evas, inst->name); else inst->ui.name = e_widget_label_add(evas, "No modem available"); e_widget_table_object_append(inst->ui.table, inst->ui.name, 0, 0, 1, 1, 1, 1, 1, 1); evas_object_show(inst->ui.name); inst->int_powered = inst->powered; inst->ui.powered = e_widget_check_add(evas, _("Powered"), &inst->int_powered); e_widget_table_object_append(inst->ui.table, inst->ui.powered, 0, 1, 1, 1, 1, 1, 1, 1); if (inst->powered_pending) e_widget_disabled_set(inst->ui.powered, (int)EINA_TRUE); evas_object_show(inst->ui.powered); evas_object_smart_callback_add(inst->ui.powered, "changed", _ofono_popup_cb_powered_changed, inst); _ofono_popup_update(inst); e_widget_size_min_get(inst->ui.table, &mw, &mh); e_widget_size_min_set(inst->ui.table, mw, mh); e_gadcon_popup_content_set(inst->popup, inst->ui.table); e_gadcon_popup_show(inst->popup); _ofono_popup_input_window_create(inst); } static void _ofono_menu_cb_post(void *data, E_Menu *menu __UNUSED__) { E_Ofono_Instance *inst = data; if ((!inst) || (!inst->menu)) return; if (inst->menu) { e_object_del(E_OBJECT(inst->menu)); inst->menu = NULL; } } static void _ofono_menu_new(E_Ofono_Instance *inst, Evas_Event_Mouse_Down *ev) { E_Zone *zone; E_Menu *m; int x, y; zone = e_util_zone_current_get(e_manager_current_get()); m = e_menu_new(); m = e_gadcon_client_util_menu_items_append(inst->gcc, m, 0); e_menu_post_deactivate_callback_set(m, _ofono_menu_cb_post, inst); inst->menu = m; e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &x, &y, NULL, NULL); e_menu_activate_mouse(m, zone, x + ev->output.x, y + ev->output.y, 1, 1, E_MENU_POP_DIRECTION_AUTO, ev->timestamp); evas_event_feed_mouse_up(inst->gcc->gadcon->evas, ev->button, EVAS_BUTTON_NONE, ev->timestamp, NULL); } static void _ofono_tip_new(E_Ofono_Instance *inst) { Evas *e; inst->tip = e_gadcon_popup_new(inst->gcc); if (!inst->tip) return; e = inst->tip->win->evas; inst->o_tip = edje_object_add(e); e_theme_edje_object_set(inst->o_tip, "base/theme/modules/ofono/tip", "e/modules/ofono/tip"); _ofono_tip_update(inst); e_gadcon_popup_content_set(inst->tip, inst->o_tip); e_gadcon_popup_show(inst->tip); } static void _ofono_tip_del(E_Ofono_Instance *inst) { evas_object_del(inst->o_tip); e_object_del(E_OBJECT(inst->tip)); inst->tip = NULL; inst->o_tip = NULL; } static void _ofono_cb_mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event) { E_Ofono_Instance *inst; Evas_Event_Mouse_Down *ev; inst = data; if (!inst) return; ev = event; if (ev->button == 1) { if (!inst->popup) _ofono_popup_new(inst); else _ofono_popup_del(inst); } else if (ev->button == 2) _ofono_popup_cb_powered_changed(inst, inst->ui.powered, NULL); else if ((ev->button == 3) && (!inst->menu)) _ofono_menu_new(inst, ev); } static void _ofono_cb_mouse_in(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__) { E_Ofono_Instance *inst = data; if (inst->tip) return; _ofono_tip_new(inst); } static void _ofono_cb_mouse_out(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__) { E_Ofono_Instance *inst = data; if (!inst->tip) return; _ofono_tip_del(inst); } static void _ofono_edje_view_update(E_Ofono_Instance *inst, Evas_Object *o) { Edje_Message_Int msg; char buf[128]; if (!inst->ctxt->has_manager) { edje_object_signal_emit(o, "e,unavailable", "e"); edje_object_part_text_set(o, "e.text.error", _("ofonod is not running")); return; } edje_object_signal_emit(o, "e,available", "e"); if (inst->name) edje_object_part_text_set(o, "e.text.name", inst->name); else edje_object_part_text_set(o, "e.text.name", _("Unknown name")); if (!inst->powered) { edje_object_part_text_set(o, "e.text.error", _("Modem powered off")); edje_object_signal_emit(o, "e,netinfo,unavailable", "e"); return; } if (inst->status) { snprintf(buf, sizeof(buf), "%c%s", toupper(inst->status[0]), inst->status + 1); edje_object_part_text_set(o, "e.text.status", buf); edje_object_signal_emit(o, "e,netinfo,available", "e"); } else edje_object_part_text_set(o, "e.text.status", _("Unknown status")); if (inst->op) { edje_object_part_text_set(o, "e.text.op", inst->op); edje_object_signal_emit(o, "e,netinfo,available", "e"); } else edje_object_part_text_set(o, "e.text.op", _("Unknown operator")); msg.val = inst->strength; edje_object_message_send(o, EDJE_MESSAGE_INT, 1, &msg); } static void _ofono_tip_update(E_Ofono_Instance *inst) { _ofono_edje_view_update(inst, inst->o_tip); } static void _ofono_gadget_update(E_Ofono_Instance *inst) { E_Ofono_Module_Context *ctxt = inst->ctxt; if (!ctxt->has_manager && inst->popup) _ofono_popup_del(inst); if (inst->popup) _ofono_popup_update(inst); if (inst->tip) _ofono_tip_update(inst); _ofono_edje_view_update(inst, inst->ui.gadget); } /* Gadcon Api Functions */ static E_Gadcon_Client * _gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style) { E_Ofono_Instance *inst; E_Ofono_Module_Context *ctxt; if (!ofono_mod) return NULL; ctxt = ofono_mod->data; inst = E_NEW(E_Ofono_Instance, 1); inst->ctxt = ctxt; inst->ui.gadget = edje_object_add(gc->evas); e_theme_edje_object_set(inst->ui.gadget, "base/theme/modules/ofono", "e/modules/ofono/main"); inst->path = NULL; inst->name = NULL; inst->powered = EINA_FALSE; inst->int_powered = 0; inst->status = NULL; inst->op = NULL; inst->strength = 0; inst->modem_element = NULL; inst->netreg_element = NULL; inst->gcc = e_gadcon_client_new(gc, name, id, style, inst->ui.gadget); inst->gcc->data = inst; evas_object_event_callback_add (inst->ui.gadget, EVAS_CALLBACK_MOUSE_DOWN, _ofono_cb_mouse_down, inst); evas_object_event_callback_add (inst->ui.gadget, EVAS_CALLBACK_MOUSE_IN, _ofono_cb_mouse_in, inst); evas_object_event_callback_add (inst->ui.gadget, EVAS_CALLBACK_MOUSE_OUT, _ofono_cb_mouse_out, inst); _ofono_gadget_update(inst); ctxt->instances = eina_list_append(ctxt->instances, inst); return inst->gcc; } static void _gc_shutdown(E_Gadcon_Client *gcc) { E_Ofono_Module_Context *ctxt; E_Ofono_Instance *inst; if (!ofono_mod) return; ctxt = ofono_mod->data; if (!ctxt) return; inst = gcc->data; if (!inst) return; if (inst->menu) { e_menu_post_deactivate_callback_set(inst->menu, NULL, NULL); e_object_del(E_OBJECT(inst->menu)); } if (inst->popup) _ofono_popup_del(inst); if (inst->tip) _ofono_tip_del(inst); evas_object_del(inst->ui.gadget); eina_stringshare_del(inst->path); eina_stringshare_del(inst->name); eina_stringshare_del(inst->status); eina_stringshare_del(inst->op); ctxt->instances = eina_list_remove(ctxt->instances, inst); E_FREE(inst); } static void _gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient __UNUSED__) { e_gadcon_client_aspect_set(gcc, 16, 16); e_gadcon_client_min_size_set(gcc, 16, 16); } static char * _gc_label(E_Gadcon_Client_Class *client_class __UNUSED__) { return _(_e_ofono_Name); } static Evas_Object * _gc_icon(E_Gadcon_Client_Class *client_class __UNUSED__, Evas *evas) { Evas_Object *o; o = edje_object_add(evas); edje_object_file_set(o, e_ofono_theme_path(), "icon"); return o; } static const char * _gc_id_new(E_Gadcon_Client_Class *client_class __UNUSED__) { E_Ofono_Module_Context *ctxt; Eina_List *instances; if (!ofono_mod) return NULL; ctxt = ofono_mod->data; if (!ctxt) return NULL; instances = ctxt->instances; snprintf(tmpbuf, sizeof(tmpbuf), "ofono.%d", eina_list_count(instances)); return tmpbuf; } static const E_Gadcon_Client_Class _gc_class = { GADCON_CLIENT_CLASS_VERSION, _e_ofono_name, { _gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL, e_gadcon_site_is_not_toolbar }, E_GADCON_CLIENT_STYLE_PLAIN }; EAPI E_Module_Api e_modapi = {E_MODULE_API_VERSION, _e_ofono_Name}; static Eina_Bool _ofono_manager_changed_do(void *data) { E_Ofono_Module_Context *ctxt = data; ctxt->poller.manager_changed = NULL; return ECORE_CALLBACK_CANCEL; } static void _ofono_manager_changed(void *data, const E_Ofono_Element *element __UNUSED__) { E_Ofono_Module_Context *ctxt = data; if (ctxt->poller.manager_changed) ecore_poller_del(ctxt->poller.manager_changed); ctxt->poller.manager_changed = ecore_poller_add (ECORE_POLLER_CORE, 1, _ofono_manager_changed_do, ctxt); } static Eina_Bool _ofono_event_manager_in(void *data, int type __UNUSED__, void *event __UNUSED__) { E_Ofono_Element *element; E_Ofono_Module_Context *ctxt = data; E_Ofono_Instance *inst; Eina_List *l; DBG("manager in"); ctxt->has_manager = EINA_TRUE; element = e_ofono_manager_get(); e_ofono_element_listener_add(element, _ofono_manager_changed, ctxt, NULL); EINA_LIST_FOREACH(ctxt->instances, l, inst) _ofono_gadget_update(inst); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _ofono_event_manager_out(void *data, int type __UNUSED__, void *event __UNUSED__) { E_Ofono_Module_Context *ctxt = data; E_Ofono_Instance *inst; Eina_List *l; DBG("manager out"); ctxt->has_manager = EINA_FALSE; EINA_LIST_FOREACH(ctxt->instances, l, inst) _ofono_gadget_update(inst); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _eofono_event_element_add(void *data, int type __UNUSED__, void *info) { E_Ofono_Element *element = info; E_Ofono_Module_Context *ctxt = data; E_Ofono_Instance *inst; Eina_List *l; Eina_Bool have_inst = EINA_FALSE; DBG(">>> %s %s", element->path, element->interface); /* is there any instance taking care of this modem already? */ EINA_LIST_FOREACH(ctxt->instances, l, inst) if ((inst->path) && (inst->path == element->path)) { have_inst = EINA_TRUE; break; } /* if no instance is handling this, is there any instance available */ if ((!have_inst) && (e_ofono_element_is_modem(element))) EINA_LIST_FOREACH(ctxt->instances, l, inst) if (!inst->path) { inst->path = eina_stringshare_ref(element->path); DBG("bound %s to an ofono module instance", inst->path); have_inst = EINA_TRUE; break; } /* if still orphan, do nothing */ if (!have_inst) return ECORE_CALLBACK_PASS_ON; if (e_ofono_element_is_modem(element)) inst->modem_element = element; else if (e_ofono_element_is_netreg(element)) inst->netreg_element = element; _ofono_gadget_update(inst); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _eofono_event_element_del(void *data, int type __UNUSED__, void *info) { E_Ofono_Element *element = info; E_Ofono_Module_Context *ctxt = data; E_Ofono_Instance *inst; Eina_List *l; Eina_Bool inst_found = EINA_FALSE; DBG("<<< %s %s", element->path, element->interface); EINA_LIST_FOREACH(ctxt->instances, l, inst) if ((inst->path) && (inst->path == element->path)) { inst_found = EINA_TRUE; break; } if (!inst_found) return ECORE_CALLBACK_PASS_ON; if (e_ofono_element_is_modem(element)) { inst->modem_element = NULL; eina_stringshare_replace(&inst->name, NULL); inst->powered = EINA_FALSE; } else if (e_ofono_element_is_netreg(element)) { inst->netreg_element = NULL; eina_stringshare_replace(&inst->status, NULL); eina_stringshare_replace(&inst->op, NULL); inst->strength = 0; } _ofono_gadget_update(inst); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _eofono_event_element_updated(void *data, int type __UNUSED__, void *event_info) { E_Ofono_Element *element = event_info; E_Ofono_Module_Context *ctxt = data; E_Ofono_Instance *inst; Eina_List *l; Eina_Bool inst_found = EINA_FALSE; const char *tmp; DBG("!!! %s %s", element->path, element->interface); EINA_LIST_FOREACH(ctxt->instances, l, inst) if ((inst->path) && (inst->path == element->path)) { inst_found = EINA_TRUE; break; } if (!inst_found) return ECORE_CALLBACK_PASS_ON; if (e_ofono_element_is_modem(element)) { if (!e_ofono_modem_powered_get(element, &(inst->powered))) inst->powered = 0; if (!e_ofono_modem_name_get(element, &tmp)) tmp = NULL; if ((!tmp) || (!tmp[0])) tmp = inst->path; eina_stringshare_replace(&inst->name, tmp); DBG("!!! powered = %d, name = %s", inst->powered, inst->name); } else if (e_ofono_element_is_netreg(element)) { if (!e_ofono_netreg_status_get(element, &tmp)) tmp = NULL; eina_stringshare_replace(&inst->status, tmp); if (!e_ofono_netreg_operator_get(element, &tmp)) tmp = NULL; eina_stringshare_replace(&inst->op, tmp); if (!e_ofono_netreg_strength_get(element, &(inst->strength))) inst->strength = 0; DBG("!!! status = %s, operator = %s, strength = %d", inst->status, inst->op, inst->strength); } _ofono_gadget_update(inst); return ECORE_CALLBACK_PASS_ON; } static void _ofono_events_register(E_Ofono_Module_Context *ctxt) { ctxt->event.manager_in = ecore_event_handler_add (E_OFONO_EVENT_MANAGER_IN, _ofono_event_manager_in, ctxt); ctxt->event.manager_out = ecore_event_handler_add (E_OFONO_EVENT_MANAGER_OUT, _ofono_event_manager_out, ctxt); ctxt->event.element_add = ecore_event_handler_add (E_OFONO_EVENT_ELEMENT_ADD, _eofono_event_element_add, ctxt); ctxt->event.element_del = ecore_event_handler_add (E_OFONO_EVENT_ELEMENT_DEL, _eofono_event_element_del, ctxt); ctxt->event.element_updated = ecore_event_handler_add (E_OFONO_EVENT_ELEMENT_UPDATED, _eofono_event_element_updated, ctxt); } static void _ofono_events_unregister(E_Ofono_Module_Context *ctxt) { if (ctxt->event.manager_in) ecore_event_handler_del(ctxt->event.manager_in); if (ctxt->event.manager_out) ecore_event_handler_del(ctxt->event.manager_out); if (ctxt->event.element_add) ecore_event_handler_del(ctxt->event.element_add); if (ctxt->event.element_del) ecore_event_handler_del(ctxt->event.element_del); if (ctxt->event.element_updated) ecore_event_handler_del(ctxt->event.element_updated); } EAPI void * e_modapi_init(E_Module *m) { E_Ofono_Module_Context *ctxt; E_DBus_Connection *c; c = e_dbus_bus_get(DBUS_BUS_SYSTEM); if (!c) goto error_dbus_bus_get; if (!e_ofono_system_init(c)) goto error_ofono_system_init; ctxt = E_NEW(E_Ofono_Module_Context, 1); if (!ctxt) goto error_ofono_context; ofono_mod = m; if (_e_ofono_module_log_dom < 0) { _e_ofono_module_log_dom = eina_log_domain_register("e_module_ofono", EINA_COLOR_ORANGE); if (_e_ofono_module_log_dom < 0) { EINA_LOG_CRIT("could not register logging domain e_module_ofono"); goto error_log_domain; } } e_gadcon_provider_register(&_gc_class); _ofono_events_register(ctxt); return ctxt; error_log_domain: _e_ofono_module_log_dom = -1; ofono_mod = NULL; E_FREE(ctxt); error_ofono_context: e_ofono_system_shutdown(); error_ofono_system_init: error_dbus_bus_get: return NULL; } static void _ofono_instances_free(E_Ofono_Module_Context *ctxt) { while (ctxt->instances) { E_Ofono_Instance *inst; inst = ctxt->instances->data; if (inst->popup) _ofono_popup_del(inst); if (inst->tip) _ofono_tip_del(inst); e_object_del(E_OBJECT(inst->gcc)); } } EAPI int e_modapi_shutdown(E_Module *m) { E_Ofono_Module_Context *ctxt; E_Ofono_Element *element; ctxt = m->data; if (!ctxt) return 0; element = e_ofono_manager_get(); e_ofono_element_listener_del(element, _ofono_manager_changed, ctxt); _ofono_events_unregister(ctxt); _ofono_instances_free(ctxt); e_gadcon_provider_unregister(&_gc_class); if (ctxt->poller.manager_changed) ecore_poller_del(ctxt->poller.manager_changed); E_FREE(ctxt); ofono_mod = NULL; e_ofono_system_shutdown(); return 1; } EAPI int e_modapi_save(E_Module *m) { E_Ofono_Module_Context *ctxt; ctxt = m->data; if (!ctxt) return 0; return 1; }