diff --git a/configure.ac b/configure.ac index f0c68b0ed..8b975dd13 100644 --- a/configure.ac +++ b/configure.ac @@ -458,6 +458,15 @@ define([CHECK_MODULE_BLUEZ], AC_SUBST(EBLUEZ_CFLAGS) AC_SUBST(EBLUEZ_LIBS) +AM_CONDITIONAL(HAVE_EOFONO, false) +define([CHECK_MODULE_OFONO], +[ + AC_E_CHECK_PKG(EOFONO, [edbus eofono], + [], [EOFONO=false]) +]) +AC_SUBST(EOFONO_CFLAGS) +AC_SUBST(EOFONO_LIBS) + AC_E_OPTIONAL_MODULE([ibar], true) AC_E_OPTIONAL_MODULE([dropshadow], true) AC_E_OPTIONAL_MODULE([clock], true) @@ -518,6 +527,7 @@ AC_E_OPTIONAL_MODULE([gadman], true) AC_E_OPTIONAL_MODULE([mixer], true, [CHECK_MODULE_MIXER]) AC_E_OPTIONAL_MODULE([connman], true, [CHECK_MODULE_CONNMAN]) AC_E_OPTIONAL_MODULE([bluez], true, [CHECK_MODULE_BLUEZ]) +AC_E_OPTIONAL_MODULE([ofono], true, [CHECK_MODULE_OFONO]) AC_E_OPTIONAL_MODULE([illume], true) AC_E_OPTIONAL_MODULE([illume2], true) AC_E_OPTIONAL_MODULE([syscon], true) @@ -652,6 +662,8 @@ src/modules/connman/Makefile src/modules/connman/module.desktop src/modules/bluez/Makefile src/modules/bluez/module.desktop +src/modules/ofono/Makefile +src/modules/ofono/module.desktop src/modules/illume/Makefile src/modules/illume/module.desktop src/modules/illume/keyboards/Makefile diff --git a/data/themes/default.edc b/data/themes/default.edc index 45ac07474..7ee09388f 100644 --- a/data/themes/default.edc +++ b/data/themes/default.edc @@ -8650,6 +8650,547 @@ collections { /* begin the collection of edje groups that are in this file */ } } +///////////////////////////////////////////////////////////////////////////// + /*** MOD: OFONO ***/ + +// GADGET and TIP all have the same parts and signals: +// +// PARTS: +// e.text.name +// e.text.status +// e.text.op +// +// SIGNALS: +// e,unavailable: ofonod is not running (nothing else works) +// e,available: ofonod is running +// e,name,available: there is info about device name +// e,name,unavailable: there is no info about device name +// e,netinfo,available: there is info about network +// e,netinfo,unavailable: there is no info about network +// +// MESSAGES: +// id=1, type=MSG_INT, description=strength (0-100) + + group { name: "e/modules/ofono/main"; + max: 128 128; + min: 1 1; + + images { + image: "gsm_0.png" COMP; + image: "gsm_1.png" COMP; + image: "gsm_2.png" COMP; + image: "gsm_3.png" COMP; + image: "gsm_4.png" COMP; + image: "gsm_no.png" COMP; + } + + script { + public message(Msg_Type:type, id, ...) { + if ((type == MSG_INT) && (id == 1)) { + new strength; + strength = getarg(2); + if (strength >= 80) + run_program(PROGRAM:"strength,5"); + else if (strength >= 60) + run_program(PROGRAM:"strength,4"); + else if (strength >= 40) + run_program(PROGRAM:"strength,3"); + else if (strength >= 20) + run_program(PROGRAM:"strength,2"); + else if (strength >= 1) + run_program(PROGRAM:"strength,1"); + else + run_program(PROGRAM:"strength,no"); + } + } + } + + parts { + part { + name: "eventarea"; + type: RECT; + mouse_events: 1; + description { + state: "default" 0.0; + color: 255 255 255 0; + } + } + + part { + name: "eventarea.image"; + type: IMAGE; + description { + state: "default" 0.0; + aspect: 1.6 1.7; + aspect_preference: HORIZONTAL; + image.normal: "gsm_no.png"; + rel1.to: "eventarea"; + rel2.to: "eventarea"; + } + description { + state: "strength,5" 0.0; + inherit: "default" 0.0; + image.normal: "gsm_4.png"; + } + description { + state: "strength,4" 0.0; + inherit: "default" 0.0; + image.normal: "gsm_3.png"; + } + description { + state: "strength,3" 0.0; + inherit: "default" 0.0; + image.normal: "gsm_2.png"; + } + description { + state: "strength,2" 0.0; + inherit: "default" 0.0; + image.normal: "gsm_1.png"; + } + description { + state: "strength,1" 0.0; + inherit: "default" 0.0; + image.normal: "gsm_0.png"; + } + description { + state: "strength,no" 0.0; + inherit: "default" 0.0; + image.normal: "gsm_no.png"; + } + description { + state: "disabled" 0.0; + inherit: "default" 0.0; + color: 255 255 255 100; + } + } + programs { + program { + name: "strength,5"; + action: STATE_SET "strength,5" 0.0; + target: "eventarea.image"; + } + program { + name: "strength,4"; + action: STATE_SET "strength,4" 0.0; + target: "eventarea.image"; + } + program { + name: "strength,3"; + action: STATE_SET "strength,3" 0.0; + target: "eventarea.image"; + } + program { + name: "strength,2"; + action: STATE_SET "strength,2" 0.0; + target: "eventarea.image"; + } + program { + name: "strength,1"; + action: STATE_SET "strength,1" 0.0; + target: "eventarea.image"; + } + program { + name: "strength,0"; + action: STATE_SET "strength,0" 0.0; + target: "eventarea.image"; + } + program { + name: "strength,no"; + action: STATE_SET "strength,no" 0.0; + target: "eventarea.image"; + } + program { + name: "e,available"; + signal: "e,available"; + source: "e"; + action: STATE_SET "default" 0.0; + target: "eventarea.image"; + } + program { + name: "e,unavailable"; + signal: "e,unavailable"; + source: "e"; + action: STATE_SET "disabled" 0.0; + target: "eventarea.image"; + } + program { + name: "netinfo,unavailable"; + signal: "e,netinfo,unavailable"; + source: "e"; + action: STATE_SET "default" 0.0; + target: "eventarea.image"; + } + } + + part { + name: "e.text.name"; + type: TEXT; + mouse_events: 0; + effect: SOFT_SHADOW; + description { + state: "default" 0.0; + color: 224 224 224 255; + color3: 0 0 0 64; + align: 0.5 1.0; + rel1 { + relative: 0.0 1.0; + offset: 0 -20; + } + rel2 { + relative: 1.0 1.0; + offset: -1 -1; + } + text { + font: "Sans"; + size: 8; + align: 0.5 1.0; + text: ""; + min: 0 1; + } + } + description { + state: "hidden" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + programs { + program { + name: "resize"; + signal: "resize"; + script { + new x, y, w, h; + get_geometry(PART:"eventarea", x, y, w, h); + if (w <= 32) + set_state(PART:"e.text.name", "hidden", 0.0); + else + set_state(PART:"e.text.name", "default", 0.0); + } + } + } + + } + } + + group { name: "e/modules/ofono/tip"; + min: 220 80; + + images { + image: "inset_sunk.png" COMP; + } + + script { + public message(Msg_Type:type, id, ...) { + if ((type == MSG_INT) && (id == 1)) { + new strength; + new Float:val; + + strength = getarg(2); + val = float(strength) / 100.0; + set_drag(PART:"strength_gauge_knob", val, 0.0); + } + } + } + + parts { + + part { name: "e.text.error"; + type: TEXT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 150 150 150 255; + fixed: 1 1; + visible: 0; + text { + font: "Sans:style=Bold"; + size: 16; + text: ""; + min: 1 1; + } + } + description { + state: "shown" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + programs { + program { + name: "error,e,available"; + signal: "e,available"; + source: "e"; + action: STATE_SET "default" 0.0; + target: "e.text.error"; + } + program { + name: "error,e,unavailable"; + signal: "e,unavailable"; + source: "e"; + action: STATE_SET "shown" 0.0; + target: "e.text.error"; + } + program { + name: "error,netinfo,available"; + signal: "e,netinfo,available"; + source: "e"; + action: STATE_SET "default" 0.0; + target: "e.text.error"; + } + program { + name: "error,netinfo,unavailable"; + signal: "e,netinfo,unavailable"; + source: "e"; + action: STATE_SET "shown" 0.0; + target: "e.text.error"; + } + } + + part { name: "e.text.name"; + type: TEXT; + mouse_events: 0; + effect: SOFT_SHADOW; + description { + state: "default" 0.0; + color: 240 240 240 255; + color3: 0 0 0 64; + align: 0.0 0.0; + fixed: 1 1; + visible: 0; + rel1 { + relative: 0.0 0.0; + offset: 10 5; + } + text { + font: "Sans:style=Bold"; + size: 16; + align: 0.0 0.0; + text: ""; + min: 1 1; + } + } + description { + state: "shown" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + programs { + program { + name: "name,available"; + signal: "e,available"; + source: "e"; + action: STATE_SET "default" 0.0; + target: "e.text.name"; + } + program { + name: "name,unavailable"; + signal: "e,unavailable"; + source: "e"; + action: STATE_SET "shown" 0.0; + target: "e.text.name"; + } + } + + part { + name: "e.text.op"; + type: TEXT; + mouse_events: 0; + effect: SOFT_SHADOW; + description { + state: "default" 0.0; + color: 240 240 240 255; + color3: 0 0 0 64; + align: 0.0 0.0; + fixed: 1 1; + visible: 1; + rel1 { + relative: 0.0 0.0; + offset: 10 5; + } + text { + font: "Sans:style=Bold"; + size: 16; + align: 0.0 0.0; + text: ""; + min: 1 1; + } + } + description { + state: "hidden" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + programs { + program { + name: "op,available"; + signal: "e,available"; + source: "e"; + action: STATE_SET "default" 0.0; + target: "e.text.op"; + } + program { + name: "op,unavailable"; + signal: "e,unavailable"; + source: "e"; + action: STATE_SET "hidden" 0.0; + target: "e.text.op"; + } + program { + name: "op,netinfo,unavailable"; + signal: "e,netinfo,unavailable"; + source: "e"; + action: STATE_SET "hidden" 0.0; + target: "e.text.op"; + } + } + + part { name: "e.text.status"; + type: TEXT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 0 0 0 255; + align: 0.0 0.0; + fixed: 1 1; + visible: 0; + rel1 { + relative: 0.0 0.0; + offset: 10 30; + } + text { + font: "Sans"; + size: 10; + align: 0.0 0.0; + text: ""; + min: 1 1; + } + } + description { + state: "shown" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + programs { + program { + name: "status,available"; + signal: "e,netinfo,available"; + source: "e"; + action: STATE_SET "shown" 0.0; + target: "e.text.status"; + } + program { + name: "status,unavailable"; + signal: "e,netinfo,unavailable"; + source: "e"; + action: STATE_SET "default" 0.0; + target: "e.text.status"; + } + } + + part { name: "strength_gauge_bg"; + type: IMAGE; + scale: 1; + mouse_events: 0; + description { + state: "default" 0.0; + min: 100 10; + max: 99999 99999; + visible: 0; + rel1 { + relative: 0.0 0.0; + offset: 10 55; + } + rel2 { + relative: 1.0 1.0; + offset: -10 -10; + } + image { + normal: "inset_sunk.png"; + border: 6 6 6 6; + } + } + description { + state: "shown" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + programs { + program { + name: "strength,available"; + signal: "e,netinfo,available"; + source: "e"; + action: STATE_SET "shown" 0.0; + target: "strength_gauge_bg"; + } + program { + name: "strength,unavailable"; + signal: "e,netinfo,unavailable"; + source: "e"; + action: STATE_SET "default" 0.0; + target: "strength_gauge_bg"; + } + } + + part { name: "strength_gauge_confine"; + type: RECT; + scale: 1; + mouse_events: 0; + description { + state: "default" 0.0; + color: 255 255 255 0; + visible: 0; + rel1 { + to: "strength_gauge_bg"; + offset: 1 1; + } + rel2 { + to: "strength_gauge_bg"; + offset: -2 -2; + } + } + } + + part { name: "strength_gauge_knob"; + mouse_events: 0; + scale: 1; + type: RECT; + dragable { + x: 1 1 0; + y: 0 0 0; + confine: "strength_gauge_confine"; + confine: "strength_gauge_bg"; + } + description { + state: "default" 0.0; + color: 255 255 255 0; + visible: 0; + min: 0 0; + max: 0 0; + } + } + + part { name: "strength_gauge_fill"; + mouse_events: 0; + type: RECT; + description { + state: "default" 0.0; + color: 55 55 55 100; + fixed: 1 1; + rel1.to: "strength_gauge_confine"; + rel2 { + to_x: "strength_gauge_knob"; + to_y: "strength_gauge_confine"; + } + } + } + + } + } + ///////////////////////////////////////////////////////////////////////////// /*** MOD: CONF_EDGEBINDINGS ***/ /* This group draws the edge and corners for the user to pick. diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am index 4b8553d65..44dba2c26 100644 --- a/src/modules/Makefile.am +++ b/src/modules/Makefile.am @@ -266,6 +266,9 @@ if USE_MODULE_COMP SUBDIRS += comp endif +if USE_MODULE_OFONO +SUBDIRS += ofono +endif DIST_SUBDIRS = \ ibar \ @@ -340,4 +343,5 @@ illume-mode-toggle \ syscon \ everything \ systray \ -comp +comp \ +ofono diff --git a/src/modules/ofono/Makefile.am b/src/modules/ofono/Makefile.am new file mode 100644 index 000000000..6406a0bd5 --- /dev/null +++ b/src/modules/ofono/Makefile.am @@ -0,0 +1,32 @@ +MAINTAINERCLEANFILES = Makefile.in +MODULE = ofono + +# data files for the module +filesdir = $(libdir)/enlightenment/modules/$(MODULE) +files_DATA = \ +e-module-$(MODULE).edj module.desktop + +EXTRA_DIST = $(files_DATA) + +# the module .so file +INCLUDES = -I. \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src/modules/$(MODULE) \ + -I$(top_srcdir)/src/bin \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/modules \ + @e_cflags@ @EOFONO_CFLAGS@ + +pkgdir = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH) + +pkg_LTLIBRARIES = module.la + +module_la_SOURCES = e_mod_main.h \ + e_mod_main.c + +module_la_LIBADD = @e_libs@ @dlopen_libs@ @EOFONO_LIBS@ +module_la_LDFLAGS = -module -avoid-version +module_la_DEPENDENCIES = $(top_builddir)/config.h + +uninstall: + rm -rf $(DESTDIR)$(libdir)/enlightenment/modules/$(MODULE) diff --git a/src/modules/ofono/e_mod_main.c b/src/modules/ofono/e_mod_main.c new file mode 100644 index 000000000..ffa18dfa1 --- /dev/null +++ b/src/modules/ofono/e_mod_main.c @@ -0,0 +1,866 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +/* 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 int +_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 1; + + _ofono_popup_del(inst); + + return 1; +} + +static int +_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 1; + + keysym = ev->key; + if (!strcmp(keysym, "Escape")) + _ofono_popup_del(inst); + + return 1; +} + +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, !inst->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) +{ + E_Ofono_Module_Context *ctxt = inst->ctxt; + 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 *mn; + E_Menu_Item *mi; + int x, y; + + zone = e_util_zone_current_get(e_manager_current_get()); + + mn = e_menu_new(); + e_menu_post_deactivate_callback_set(mn, _ofono_menu_cb_post, inst); + inst->menu = mn; + + e_gadcon_client_util_menu_items_append(inst->gcc, mn, 0); + e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &x, &y, NULL, NULL); + e_menu_activate_mouse(mn, 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 int +_ofono_manager_changed_do(void *data) +{ + E_Ofono_Module_Context *ctxt = data; + + ctxt->poller.manager_changed = NULL; + return 0; +} + +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 int +_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 1; +} + +static int +_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 1; +} + +static int +_eofono_event_element_add(void *data, int type, 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_RENEW; + + 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_RENEW; +} + +static int +_eofono_event_element_del(void *data, int type, 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_RENEW; + + 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_RENEW; +} + +static int +_eofono_event_element_updated(void *data, int type, 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_RENEW; + + 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_RENEW; +} + +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; +} diff --git a/src/modules/ofono/e_mod_main.h b/src/modules/ofono/e_mod_main.h new file mode 100644 index 000000000..51c702e6a --- /dev/null +++ b/src/modules/ofono/e_mod_main.h @@ -0,0 +1,117 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ +#ifndef E_MOD_MAIN_H +#define E_MOD_MAIN_H + +#include "config.h" +#include +#include +#include + +#define MOD_CONF_VERSION 2 + +extern int _e_ofono_module_log_dom; +#define DBG(...) EINA_LOG_DOM_DBG(_e_ofono_module_log_dom, __VA_ARGS__) +#define WRN(...) EINA_LOG_DOM_WARN(_e_ofono_module_log_dom, __VA_ARGS__) +#define CRIT(...) EINA_LOG_DOM_CRIT(_e_ofono_module_log_dom, __VA_ARGS__) +#define ERR(...) EINA_LOG_DOM_ERR(_e_ofono_module_log_dom, __VA_ARGS__) + +typedef struct E_Ofono_Instance E_Ofono_Instance; +typedef struct E_Ofono_Module_Context E_Ofono_Module_Context; + +struct E_Ofono_Instance +{ + E_Ofono_Module_Context *ctxt; + E_Gadcon_Client *gcc; + E_Gadcon_Popup *popup; + E_Menu *menu; + + struct + { + Evas_Object *gadget; + Evas_Object *table; + Evas_Object *name; + Evas_Object *powered; + struct + { + Ecore_X_Window win; + Ecore_Event_Handler *mouse_up; + Ecore_Event_Handler *key_down; + } input; + } ui; + + E_Gadcon_Popup *tip; + Evas_Object *o_tip; + + /* e_dbus ofono element pointers */ + E_Ofono_Element *modem_element; + E_Ofono_Element *netreg_element; + + /* modem data */ + const char *path; + const char *name; + const char *status; + const char *op; + int int_powered; /* used by popup */ + Eina_Bool powered; + uint8_t strength; + + Eina_Bool powered_pending:1; +}; + +struct E_Ofono_Module_Context +{ + Eina_List *instances; + + struct + { + Ecore_Event_Handler *manager_in; + Ecore_Event_Handler *manager_out; + Ecore_Event_Handler *element_add; + Ecore_Event_Handler *element_del; + Ecore_Event_Handler *element_updated; + } event; + + struct + { + Ecore_Poller *manager_changed; + } poller; + + Eina_Bool has_manager:1; +}; + +EAPI extern E_Module_Api e_modapi; +EAPI void *e_modapi_init (E_Module *m); +EAPI int e_modapi_shutdown (E_Module *m); +EAPI int e_modapi_save (E_Module *m); + +const char *e_ofono_theme_path(void); + +static inline void +_ofono_dbus_error_show(const char *msg, const DBusError *error) +{ + const char *name; + + if ((!error) || (!dbus_error_is_set(error))) + return; + + name = error->name; + if (strncmp(name, "org.ofono.Error.", sizeof("org.ofono.Error.") - 1) == 0) + name += sizeof("org.ofono.Error.") - 1; + + e_util_dialog_show(_("Ofono Server Operation Failed"), + _("Could not execute remote operation:
" + "%s
" + "Server Error %s: %s"), + msg, name, error->message); +} + +static inline void +_ofono_operation_error_show(const char *msg) +{ + e_util_dialog_show(_("Ofono Operation Failed"), + _("Could not execute local operation:
%s"), + msg); +} +#endif diff --git a/src/modules/ofono/module.desktop.in b/src/modules/ofono/module.desktop.in new file mode 100644 index 000000000..032bacf36 --- /dev/null +++ b/src/modules/ofono/module.desktop.in @@ -0,0 +1,12 @@ +[Desktop Entry] +Type=Link +Name=Mobile Modems Manager +Name[pt_BR]=Gerenciador de modems móveis +Name[es]=Gerenciador de modems moviles +Name[it]=Gestore di modem mobili +Icon=e-module-connman +Comment=Mobile Modems Manager Gadget
Control mobile modems. +Comment[pt_BR]=Gerenciador de modems móveis
Controla modems móveis. +Comment[es]=Gerenciador de modems mobiles
Controla modems móviles +Comment[it]=Gestore di modem mobili
Controlla le modem mobili.. +X-Enlightenment-ModuleType=system