/* * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 */ #include "e.h" #include "e_mod_main.h" /* * STATUS: * * displays current status, allows connecting and * disconnecting. needs connman from git (will be 0.48, still * unreleased). * * TODO: * * MUST: * 1. request for passphrase if pass_required is set or * connect error is org.moblin.connman.Error.PassphraseRequired * 2. improve gadget ui * 3. investigate stringshare mess when manager goes out * * GOOD: * 1. imporve mouse over popup ui * 2. nice popup using edje objects as rows, not simple lists (fancy) * 3. "Controls" for detailed information, similar to Mixer app * it would contain switches to toggle offline and choose * technologies that are enabled. * * IDEAS: * 1. create static connections * */ static E_Module *connman_mod = NULL; static char tmpbuf[PATH_MAX]; /* general purpose buffer, just use immediately */ static const char _name[] = "connman"; const char _Name[] = "Connection Manager"; static const char *e_str_idle = NULL; static const char *e_str_association = NULL; static const char *e_str_configuration = NULL; static const char *e_str_ready = NULL; static const char *e_str_disconnect = NULL; static const char *e_str_failure = NULL; static void _connman_service_ask_pass_and_connect(E_Connman_Service *service); static void _connman_default_service_changed_delayed(E_Connman_Module_Context *ctxt); static void _connman_gadget_update(E_Connman_Instance *inst); static void _connman_tip_update(E_Connman_Instance *inst); static const char * e_connman_theme_path(void) { #define TF "/e-module-connman.edj" size_t dirlen; dirlen = strlen(connman_mod->dir); if (dirlen >= sizeof(tmpbuf) - sizeof(TF)) return NULL; memcpy(tmpbuf, connman_mod->dir, dirlen); memcpy(tmpbuf + dirlen, TF, sizeof(TF)); return tmpbuf; #undef TF } static inline E_Connman_Service * _connman_ctxt_find_service_stringshare(const E_Connman_Module_Context *ctxt, const char *service_path) { E_Connman_Service *itr; EINA_INLIST_FOREACH(ctxt->services, itr) if (itr->path == service_path) return itr; return NULL; } static inline void _connman_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.moblin.connman.Error.", sizeof("org.moblin.connman.Error.") - 1) == 0) name += sizeof("org.moblin.connman.Error.") - 1; e_util_dialog_show(_("Connman Server Operation Failed"), _("Could not execute remote operation:
" "%s
" "Server Error %s: %s"), msg, name, error->message); } static inline void _connman_operation_error_show(const char *msg) { e_util_dialog_show(_("Connman Operation Failed"), _("Could not execute local operation:
%s"), msg); } static void _connman_toggle_offline_mode_cb(void *data, DBusMessage *msg __UNUSED__, DBusError *error) { E_Connman_Module_Context *ctxt = data; if ((!error) || (!dbus_error_is_set(error))) { printf("DBG CONNMAN: successfuly toggled to offline mode\n"); // XXX hack: connman does not emit propertychanged for this, they need to fix it e_connman_manager_sync_elements(); _connman_default_service_changed_delayed(ctxt); return; } _connman_dbus_error_show(_("Cannot toggle system's offline mode."), error); dbus_error_free(error); } static void _connman_toggle_offline_mode_pending_cb(void *data, DBusMessage *msg, DBusError *error) { E_Connman_Module_Context *ctxt = data; ctxt->offline_mode_pending = EINA_FALSE; _connman_toggle_offline_mode_cb(data, msg, error); } static void _connman_toggle_offline_mode(E_Connman_Module_Context *ctxt) { bool offline; if ((!ctxt) || (!ctxt->has_manager)) { _connman_operation_error_show(_("ConnMan Daemon is not running.")); return; } if (!e_connman_manager_offline_mode_get(&offline)) { _connman_operation_error_show (_("Query system's offline mode.")); return; } offline = !offline; if (!e_connman_manager_offline_mode_set (offline, _connman_toggle_offline_mode_cb, ctxt)) { _connman_operation_error_show (_("Cannot toggle system's offline mode.")); return; } } static void _connman_cb_toggle_offline_mode(E_Object *obj __UNUSED__, const char *params __UNUSED__) { E_Connman_Module_Context *ctxt; if (!connman_mod) return; ctxt = connman_mod->data; _connman_toggle_offline_mode(ctxt); } struct connman_passphrase_data { void (*cb)(void *data, const char *password, const char *service_path); void *data; const char *service_path; char *passphrase; E_Connman_Module_Context *ctxt; E_Dialog *dia; Evas_Object *entry; Eina_Bool canceled; int cleartext; }; static void _connman_passphrase_ask_cleartext_changed(void *data, Evas_Object *obj, void *event __UNUSED__) { struct connman_passphrase_data *d = data; e_widget_entry_password_set(d->entry, !e_widget_check_checked_get(obj)); e_widget_entry_readonly_set(d->entry, 0); e_widget_focus_set(d->entry, 1); } static void _connman_passphrase_ask_ok(void *data, E_Dialog *dia) { struct connman_passphrase_data *d = data; d->canceled = EINA_FALSE; e_object_del(E_OBJECT(dia)); } static void _connman_passphrase_ask_cancel(void *data, E_Dialog *dia) { struct connman_passphrase_data *d = data; d->canceled = EINA_TRUE; e_object_del(E_OBJECT(dia)); } static void _connman_passphrase_ask_del(void *data) { E_Dialog *dia = data; struct connman_passphrase_data *d = e_object_data_get(E_OBJECT(dia)); if (d->canceled) { free(d->passphrase); d->passphrase = NULL; } d->cb(d->data, d->passphrase, d->service_path); eina_stringshare_del(d->service_path); free(d->passphrase); E_FREE(d); } static void _connman_passphrase_ask_key_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event) { Evas_Event_Key_Down *ev = event; struct connman_passphrase_data *d = data; if (strcmp(ev->keyname, "Return") == 0) _connman_passphrase_ask_ok(d, d->dia); else if (strcmp(ev->keyname, "Escape") == 0) _connman_passphrase_ask_cancel(d, d->dia); } static void _connman_passphrase_ask(E_Connman_Service *service, void (*cb)(void *data, const char *password, const char *service_path), const void *data) { struct connman_passphrase_data *d; Evas_Object *list, *o; Evas *evas; char buf[512]; const char *passphrase; int mw, mh; if (!cb) return; if (!service) { cb((void *)data, NULL, NULL); return; } d = E_NEW(struct connman_passphrase_data, 1); if (!d) { cb((void *)data, NULL, NULL); return; } d->cb = cb; d->data = (void *)data; d->service_path = eina_stringshare_add(service->path); d->ctxt = service->ctxt; d->canceled = EINA_TRUE; /* closing the dialog defaults to cancel */ d->dia = e_dialog_new(NULL, "E", "connman_ask_passphrase"); e_dialog_title_set(d->dia, _("ConnMan needs your passphrase")); e_dialog_icon_set(d->dia, "dialog-ask", 64); e_dialog_border_icon_set(d->dia, "dialog-ask"); evas = d->dia->win->evas; list = e_widget_list_add(evas, 0, 0); o = edje_object_add(evas); e_theme_edje_object_set(o, "base/theme/dialog", "e/widgets/dialog/text"); snprintf(buf, sizeof(buf), _("Connection Manager needs your passphrase for
" "the service %s"), service->name); edje_object_part_text_set(o, "e.textblock.message", buf); edje_object_size_min_calc(o, &mw, &mh); evas_object_size_hint_min_set(o, mw, mh); evas_object_resize(o, mw, mh); evas_object_show(o); e_widget_list_object_append(list, o, 1, 1, 0.5); if (!e_connman_service_passphrase_get(service->element, &passphrase)) passphrase = NULL; if (passphrase && passphrase[0]) d->passphrase = strdup(passphrase); else d->passphrase = NULL; d->entry = o = e_widget_entry_add(evas, &d->passphrase, NULL, NULL, NULL); e_widget_entry_password_set(o, 0); evas_object_show(o); e_widget_list_object_append(list, o, 1, 0, 0.0); #if 0 // NOT WORKING, e_widget_entry_password_set() changes stops editing!!! d->cleartext = 1; o = e_widget_check_add(evas, _("Show passphrase as clear text"), &d->cleartext); evas_object_smart_callback_add (o, "changed", _connman_passphrase_ask_cleartext_changed, d); evas_object_show(o); e_widget_list_object_append(list, o, 1, 0, 0.0); #endif e_widget_size_min_get(list, &mw, &mh); e_dialog_content_set(d->dia, list, mw, mh); e_dialog_button_add (d->dia, _("Ok"), NULL, _connman_passphrase_ask_ok, d); e_dialog_button_add (d->dia, _("Cancel"), NULL, _connman_passphrase_ask_cancel, d); evas_object_event_callback_add (d->dia->bg_object, EVAS_CALLBACK_KEY_DOWN, _connman_passphrase_ask_key_down, d); e_object_del_attach_func_set (E_OBJECT(d->dia), _connman_passphrase_ask_del); e_object_data_set(E_OBJECT(d->dia), d); e_dialog_button_focus_num(d->dia, 0); e_widget_focus_set(d->entry, 1); e_dialog_resizable_set(d->dia, 1); e_win_centered_set(d->dia->win, 1); e_dialog_show(d->dia); } static void _connman_service_free(E_Connman_Service *service) { eina_stringshare_del(service->path); eina_stringshare_del(service->name); eina_stringshare_del(service->type); eina_stringshare_del(service->mode); eina_stringshare_del(service->state); eina_stringshare_del(service->error); eina_stringshare_del(service->security); eina_stringshare_del(service->ipv4_method); eina_stringshare_del(service->ipv4_address); eina_stringshare_del(service->ipv4_netmask); E_FREE(service); } static void _connman_service_changed(void *data, const E_Connman_Element *element) { E_Connman_Service *service = data; const char *str; unsigned char u8; bool b; #define GSTR(name_, getter) \ str = NULL; \ if (!getter(element, &str)) \ str = NULL; \ if (service->name_ != str) \ printf("changing "#name_": %s (%p) with %s (%p)\n", service->name_, service->name_, str, str); \ eina_stringshare_replace(&service->name_, str) GSTR(name, e_connman_service_name_get); GSTR(type, e_connman_service_type_get); GSTR(mode, e_connman_service_mode_get); GSTR(state, e_connman_service_state_get); GSTR(error, e_connman_service_error_get); GSTR(security, e_connman_service_security_get); GSTR(ipv4_method, e_connman_service_ipv4_method_get); GSTR(ipv4_address, e_connman_service_ipv4_address_get); GSTR(ipv4_netmask, e_connman_service_ipv4_netmask_get); #undef GSTR if (!e_connman_service_strength_get(element, &u8)) u8 = 0; service->strength = u8; #define GBOOL(name_, getter) \ b = EINA_FALSE; \ if (!getter(element, &b)) \ b = EINA_FALSE; \ service->name_ = b GBOOL(favorite, e_connman_service_favorite_get); GBOOL(auto_connect, e_connman_service_auto_connect_get); GBOOL(pass_required, e_connman_service_passphrase_required_get); #undef GBOOL printf("DBG CONNMAN: service details changed: (default=%p, %hhu)\n" " name....: %s\n" " state...: %s\n" " type....: %s\n" " error...: %s\n" " security: %s\n" " strength: %hhu\n" " flags...: favorite=%hhu, auto_connect=%hhu, pass_required=%hhu\n", service->ctxt->default_service, service->ctxt->default_service == service, service->name, service->state, service->type, service->error, service->security, service->strength, service->favorite, service->auto_connect, service->pass_required); if ((service->ctxt->default_service == service) || (!service->ctxt->default_service)) _connman_default_service_changed_delayed(service->ctxt); else printf("DBG CONNMAN: do not request for delayed changed as this is not the default.\n"); } static void _connman_service_freed(void *data) { E_Connman_Service *service = data; E_Connman_Module_Context *ctxt = service->ctxt; printf("DBG CONNMAN service freed %s\n", service->name); ctxt->services = eina_inlist_remove (ctxt->services, EINA_INLIST_GET(service)); _connman_service_free(service); if (ctxt->default_service == service) { ctxt->default_service = NULL; _connman_default_service_changed_delayed(ctxt); } } static E_Connman_Service * _connman_service_new(E_Connman_Module_Context *ctxt, E_Connman_Element *element) { E_Connman_Service *service; const char *str; unsigned char u8; bool b; if (!element) return NULL; service = E_NEW(E_Connman_Service, 1); if (!service) return NULL; service->ctxt = ctxt; service->element = element; service->path = eina_stringshare_add(element->path); #define GSTR(name_, getter) \ str = NULL; \ if (!getter(element, &str)) \ str = NULL; \ service->name_ = eina_stringshare_add(str) GSTR(name, e_connman_service_name_get); GSTR(type, e_connman_service_type_get); GSTR(mode, e_connman_service_mode_get); GSTR(state, e_connman_service_state_get); GSTR(error, e_connman_service_error_get); GSTR(security, e_connman_service_security_get); GSTR(ipv4_method, e_connman_service_ipv4_method_get); GSTR(ipv4_address, e_connman_service_ipv4_address_get); GSTR(ipv4_netmask, e_connman_service_ipv4_netmask_get); #undef GSTR if (!e_connman_service_strength_get(element, &u8)) u8 = 0; service->strength = u8; #define GBOOL(name_, getter) \ b = EINA_FALSE; \ if (!getter(element, &b)) \ b = EINA_FALSE; \ service->name_ = b GBOOL(favorite, e_connman_service_favorite_get); GBOOL(auto_connect, e_connman_service_auto_connect_get); GBOOL(pass_required, e_connman_service_passphrase_required_get); #undef GBOOL e_connman_element_listener_add (element, _connman_service_changed, service, _connman_service_freed); return service; } static void _connman_service_disconnect_cb(void *data, DBusMessage *msg __UNUSED__, DBusError *error) { E_Connman_Module_Context *ctxt = data; if (error && dbus_error_is_set(error)) { if (strcmp(error->message, "org.moblin.connman.Error.NotConnected") != 0) _connman_dbus_error_show(_("Disconnect to network service."), error); dbus_error_free(error); } _connman_default_service_changed_delayed(ctxt); } static void _connman_service_disconnect(E_Connman_Service *service) { if (!e_connman_service_disconnect (service->element, _connman_service_disconnect_cb, service->ctxt)) _connman_operation_error_show(_("Disconnect to network service.")); } struct connman_service_connect_data { const char *service_path; E_Connman_Module_Context *ctxt; }; static void _connman_service_connect_cb(void *data, DBusMessage *msg __UNUSED__, DBusError *error) { struct connman_service_connect_data *d = data; if (error && dbus_error_is_set(error)) { if ((strcmp(error->name, "org.moblin.connman.Error.PassphraseRequired") == 0) || (strcmp(error->name, "org.moblin.connman.Error.Failed") == 0)) { E_Connman_Service *service; service = _connman_ctxt_find_service_stringshare (d->ctxt, d->service_path); if (!service) _connman_operation_error_show (_("Service does not exist anymore")); else { _connman_service_disconnect(service); _connman_service_ask_pass_and_connect(service); } } else if (strcmp(error->name, "org.moblin.connman.Error.AlreadyConnected") != 0) _connman_dbus_error_show(_("Connect to network service."), error); dbus_error_free(error); } _connman_default_service_changed_delayed(d->ctxt); eina_stringshare_del(d->service_path); E_FREE(d); } static void _connman_service_connect(E_Connman_Service *service) { struct connman_service_connect_data *d; d = E_NEW(struct connman_service_connect_data, 1); if (!d) return; d->service_path = eina_stringshare_ref(service->path); d->ctxt = service->ctxt; if (!e_connman_service_connect (service->element, _connman_service_connect_cb, d)) { eina_stringshare_del(d->service_path); E_FREE(d); _connman_operation_error_show(_("Connect to network service.")); } } struct connman_service_ask_pass_data { const char *service_path; E_Connman_Module_Context *ctxt; }; static void _connman_service_ask_pass_and_connect__set_cb(void *data, DBusMessage *msg __UNUSED__, DBusError *error) { struct connman_service_ask_pass_data *d = data; E_Connman_Service *service; service = _connman_ctxt_find_service_stringshare(d->ctxt, d->service_path); if (!service) { _connman_operation_error_show(_("Service does not exist anymore")); goto end; } if ((!error) || (!dbus_error_is_set(error))) _connman_service_connect(service); // TODO: check if connman reports password was invalid and ask again? end: if ((error) && (dbus_error_is_set(error))) dbus_error_free(error); eina_stringshare_del(d->service_path); E_FREE(d); } static void _connman_service_ask_pass_and_connect__ask_cb(void *data, const char *passphrase, const char *service_path) { E_Connman_Module_Context *ctxt = data; E_Connman_Service *service; struct connman_service_ask_pass_data *d; service = _connman_ctxt_find_service_stringshare(ctxt, service_path); if (!service) { _connman_operation_error_show(_("Service does not exist anymore")); return; } if (!passphrase) { _connman_service_disconnect(service); return; } d = E_NEW(struct connman_service_ask_pass_data, 1); if (!d) return; d->service_path = eina_stringshare_ref(service_path); d->ctxt = ctxt; if (!e_connman_service_passphrase_set (service->element, passphrase, _connman_service_ask_pass_and_connect__set_cb, d)) { eina_stringshare_del(d->service_path); E_FREE(d); _connman_operation_error_show(_("Could not set service's passphrase")); return; } } static void _connman_service_ask_pass_and_connect(E_Connman_Service *service) { _connman_passphrase_ask (service, _connman_service_ask_pass_and_connect__ask_cb, service->ctxt); } static void _connman_services_free(E_Connman_Module_Context *ctxt) { while (ctxt->services) { E_Connman_Service *service = (E_Connman_Service *)ctxt->services; ctxt->services = eina_inlist_remove(ctxt->services, ctxt->services); _connman_service_free(service); } } static inline Eina_Bool _connman_services_element_exists(const E_Connman_Module_Context *ctxt, const E_Connman_Element *element) { const E_Connman_Service *service; EINA_INLIST_FOREACH(ctxt->services, service) if (service->path == element->path) return EINA_TRUE; return EINA_FALSE; } static void _connman_services_load(E_Connman_Module_Context *ctxt) { unsigned int i, count; E_Connman_Element **elements; if (!e_connman_manager_services_get(&count, &elements)) return; for (i = 0; i < count; i++) { E_Connman_Element *e = elements[i]; E_Connman_Service *service; if ((!e) || (_connman_services_element_exists(ctxt, e))) { printf("DBG CONNMAN service already exists %p (%s)\n", e, e ? e->path : ""); continue; } service = _connman_service_new(ctxt, e); if (!service) continue; printf("DBG CONNMAN added service: %s\n", service->name); ctxt->services = eina_inlist_append (ctxt->services, EINA_INLIST_GET(service)); } /* no need to remove elements, as they remove themselves */ free(elements); } static void _connman_default_service_changed(E_Connman_Module_Context *ctxt) { E_Connman_Service *itr, *def = NULL; E_Connman_Instance *inst; const Eina_List *l; const char *tech; EINA_INLIST_FOREACH(ctxt->services, itr) { if (itr->state == e_str_ready) { def = itr; break; } else if ((itr->state == e_str_association) && ((!def) || (def && def->state != e_str_configuration))) def = itr; else if (itr->state == e_str_configuration) def = itr; } printf("DBG CONNMAN: default service changed to %p (%s)\n", def, def ? def->name : ""); if (!e_connman_manager_technology_default_get(&tech)) tech = NULL; eina_stringshare_replace(&ctxt->technology, tech); printf("DBG CONNMAN: manager technology is '%s'\n", tech); if (!e_connman_manager_offline_mode_get(&ctxt->offline_mode)) ctxt->offline_mode = EINA_FALSE; if ((e_config->mode.offline != ctxt->offline_mode) && (!ctxt->offline_mode_pending)) { e_config->mode.offline = ctxt->offline_mode; e_config_mode_changed(); e_config_save_queue(); } ctxt->default_service = def; EINA_LIST_FOREACH(ctxt->instances, l, inst) _connman_gadget_update(inst); } static void _connman_services_reload(E_Connman_Module_Context *ctxt) { _connman_services_load(ctxt); _connman_default_service_changed(ctxt); } static int _connman_default_service_changed_delayed_do(void *data) { E_Connman_Module_Context *ctxt = data; ctxt->poller.default_service_changed = NULL; printf("\033[32mDBG CONNMAN: do delayed change\033[0m\n"); _connman_default_service_changed(ctxt); return 0; } static void _connman_default_service_changed_delayed(E_Connman_Module_Context *ctxt) { if (!ctxt->has_manager) return; printf("\033[1;31mDBG CONNMAN: request delayed change\033[0m\n"); if (ctxt->poller.default_service_changed) ecore_poller_del(ctxt->poller.default_service_changed); ctxt->poller.default_service_changed = ecore_poller_add (ECORE_POLLER_CORE, 1, _connman_default_service_changed_delayed_do, ctxt); } static void _connman_popup_del(E_Connman_Instance *inst); static int _connman_popup_input_window_mouse_up_cb(void *data, int type __UNUSED__, void *event) { Ecore_Event_Mouse_Button *ev = event; E_Connman_Instance *inst = data; if (ev->window != inst->ui.input.win) return 1; _connman_popup_del(inst); return 1; } static int _connman_popup_input_window_key_down_cb(void *data, int type __UNUSED__, void *event) { Ecore_Event_Key *ev = event; E_Connman_Instance *inst = data; const char *keysym; if (ev->window != inst->ui.input.win) return 1; keysym = ev->key; if (strcmp(keysym, "Escape") == 0) _connman_popup_del(inst); return 1; } static void _connman_popup_input_window_destroy(E_Connman_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 _connman_popup_input_window_create(E_Connman_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, _connman_popup_input_window_mouse_up_cb, inst); inst->ui.input.key_down = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _connman_popup_input_window_key_down_cb, inst); inst->ui.input.win = w; } static void _connman_popup_cb_offline_mode_changed(void *data, Evas_Object *obj, void *event __UNUSED__) { E_Connman_Instance *inst = data; E_Connman_Module_Context *ctxt = inst->ctxt; Eina_Bool offline = e_widget_check_checked_get(obj); if ((!ctxt) || (!ctxt->has_manager)) { _connman_operation_error_show(_("ConnMan Daemon is not running.")); return; } printf(">>>> OFFLINE=%hhu\n", offline); if (!e_connman_manager_offline_mode_set (offline, _connman_toggle_offline_mode_cb, ctxt)) { _connman_operation_error_show (_("Cannot toggle system's offline mode.")); return; } } static void _connman_popup_cb_controls(void *data, void *data2 __UNUSED__) { E_Connman_Instance *inst = data; _connman_popup_del(inst); e_util_dialog_show("TODO", "TODO!"); } static void _connman_popup_service_selected(void *data) { E_Connman_Instance *inst = data; E_Connman_Module_Context *ctxt = inst->ctxt; E_Connman_Service *service; if (inst->first_selection) { inst->first_selection = EINA_FALSE; return; } if (!inst->service_path) return; service = _connman_ctxt_find_service_stringshare(ctxt, inst->service_path); if (!service) return; _connman_popup_del(inst); if (service->pass_required) _connman_service_ask_pass_and_connect(service); else if (service->state == e_str_ready) _connman_service_disconnect(service); else _connman_service_connect(service); } static void _connman_popup_update(E_Connman_Instance *inst) { Evas_Object *list = inst->ui.list; E_Connman_Service *service; const char *default_path; Evas *evas = evas_object_evas_get(list); int i, selected; char buf[128]; default_path = inst->ctxt->default_service ? inst->ctxt->default_service->path : NULL; /* TODO: replace this with a scroller + list of edje * objects that are more full of features */ e_widget_ilist_freeze(list); e_widget_ilist_clear(list); i = 0; selected = -1; EINA_INLIST_FOREACH(inst->ctxt->services, service) { Evas_Object *icon; Edje_Message_Int msg; if (service->path == default_path) selected = i; i++; snprintf(buf, sizeof(buf), "e/modules/connman/icon/%s", service->type); icon = edje_object_add(evas); e_theme_edje_object_set(icon, "base/theme/modules/connman", buf); snprintf(buf, sizeof(buf), "e,state,%s", service->state); edje_object_signal_emit(icon, buf, "e"); if (service->mode) { snprintf(buf, sizeof(buf), "e,mode,%s", service->mode); edje_object_signal_emit(icon, buf, "e"); } if (service->security) { snprintf(buf, sizeof(buf), "e,security,%s", service->security); edje_object_signal_emit(icon, buf, "e"); } if (service->favorite) edje_object_signal_emit(icon, "e,favorite,yes", "e"); else edje_object_signal_emit(icon, "e,favorite,no", "e"); if (service->auto_connect) edje_object_signal_emit(icon, "e,auto_connect,yes", "e"); else edje_object_signal_emit(icon, "e,auto_connect,no", "e"); if (service->pass_required) edje_object_signal_emit(icon, "e,pass_required,yes", "e"); else edje_object_signal_emit(icon, "e,pass_required,no", "e"); msg.val = service->strength; edje_object_message_send(icon, EDJE_MESSAGE_INT, 1, &msg); e_widget_ilist_append (list, icon, service->name, _connman_popup_service_selected, inst, service->path); } if (selected >= 0) { inst->first_selection = EINA_TRUE; e_widget_ilist_selected_set(list, selected); } else inst->first_selection = EINA_FALSE; e_widget_ilist_thaw(list); e_widget_ilist_go(list); e_widget_check_checked_set(inst->ui.offline_mode, inst->ctxt->offline_mode); } static void _connman_popup_del(E_Connman_Instance *inst) { eina_stringshare_replace(&inst->service_path, NULL); _connman_popup_input_window_destroy(inst); e_object_del(E_OBJECT(inst->popup)); inst->popup = NULL; } static void _connman_popup_new(E_Connman_Instance *inst) { E_Connman_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 (ctxt->default_service) eina_stringshare_replace(&inst->service_path, ctxt->default_service->path); // TODO: get this size from edj inst->ui.list = e_widget_ilist_add(evas, 32, 32, &inst->service_path); e_widget_size_min_set(inst->ui.list, 180, 100); e_widget_table_object_append(inst->ui.table, inst->ui.list, 0, 0, 1, 5, 1, 1, 1, 1); inst->offline_mode = ctxt->offline_mode; inst->ui.offline_mode = e_widget_check_add (evas, _("Offline mode"), &inst->offline_mode); evas_object_show(inst->ui.offline_mode); e_widget_table_object_append(inst->ui.table, inst->ui.offline_mode, 0, 5, 1, 1, 1, 1, 1, 0); evas_object_smart_callback_add (inst->ui.offline_mode, "changed", _connman_popup_cb_offline_mode_changed, inst); inst->ui.button = e_widget_button_add (evas, _("Controls"), NULL, _connman_popup_cb_controls, inst, NULL); e_widget_table_object_append(inst->ui.table, inst->ui.button, 0, 6, 1, 1, 1, 1, 1, 0); _connman_popup_update(inst); e_widget_size_min_get(inst->ui.table, &mw, &mh); if (mh < 208) mh = 208; if (mw < 200) mw = 200; 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); _connman_popup_input_window_create(inst); } static void _connman_menu_cb_post(void *data, E_Menu *menu __UNUSED__) { E_Connman_Instance *inst = data; if ((!inst) || (!inst->menu)) return; if (inst->menu) { e_object_del(E_OBJECT(inst->menu)); inst->menu = NULL; } } static void _connman_menu_cb_cfg(void *data, E_Menu *menu __UNUSED__, E_Menu_Item *mi __UNUSED__) { E_Connman_Instance *inst = data; if (!inst) return; if (inst->popup) _connman_popup_del(inst); e_util_dialog_show("TODO", "TODO!"); } static void _connman_menu_new(E_Connman_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, _connman_menu_cb_post, inst); inst->menu = mn; mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Settings")); e_util_menu_item_theme_icon_set(mi, "configure"); e_menu_item_callback_set(mi, _connman_menu_cb_cfg, inst); 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 _connman_tip_new(E_Connman_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/connman/tip", "e/modules/connman/tip"); _connman_tip_update(inst); e_gadcon_popup_content_set(inst->tip, inst->o_tip); e_gadcon_popup_show(inst->tip); } static void _connman_tip_del(E_Connman_Instance *inst) { evas_object_del(inst->o_tip); e_object_del(E_OBJECT(inst->tip)); inst->tip = NULL; inst->o_tip = NULL; } static void _connman_cb_mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event) { E_Connman_Instance *inst; Evas_Event_Mouse_Down *ev; inst = data; if (!inst) return; ev = event; if (ev->button == 1) { if (!inst->popup) _connman_popup_new(inst); else _connman_popup_del(inst); } else if (ev->button == 2) _connman_toggle_offline_mode(inst->ctxt); else if ((ev->button == 3) && (!inst->menu)) _connman_menu_new(inst, ev); } static void _connman_cb_mouse_in(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__) { E_Connman_Instance *inst = data; if (inst->tip) return; _connman_tip_new(inst); } static void _connman_cb_mouse_out(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__) { E_Connman_Instance *inst = data; if (!inst->tip) return; _connman_tip_del(inst); } static void _connman_edje_view_update(E_Connman_Instance *inst, Evas_Object *o) { E_Connman_Module_Context *ctxt = inst->ctxt; const E_Connman_Service *service; Edje_Message_Int msg; char buf[128]; if (!ctxt->has_manager) { edje_object_signal_emit(o, "e,unavailable", "e"); edje_object_part_text_set(o, "e.text.name", _("No ConnMan")); edje_object_part_text_set(o, "e.text.error", _("No ConnMan server found.")); edje_object_signal_emit(o, "e,changed,connected,no", "e"); edje_object_part_text_set(o, "e.text.offline_mode", ""); edje_object_signal_emit(o, "e,changed,offline_mode,no", "e"); return; } edje_object_signal_emit(o, "e,available", "e"); if (ctxt->offline_mode) { edje_object_signal_emit(o, "e,changed,offline_mode,yes", "e"); edje_object_part_text_set(o, "e.text.offline_mode", _("Offline mode: all radios are turned off")); } else { edje_object_signal_emit(o, "e,changed,offline_mode,no", "e"); edje_object_part_text_set(o, "e.text.offline_mode", ""); } if (ctxt->technology && ctxt->technology[0]) { edje_object_part_text_set(o, "e.text.technology", ctxt->technology); snprintf(buf, sizeof(buf), "e,changed,technology,%s", ctxt->technology); edje_object_signal_emit(o, buf, "e"); } else if (!ctxt->default_service) { edje_object_part_text_set(o, "e.text.technology", ""); edje_object_signal_emit(o, "e,changed,technology,none", "e"); } service = ctxt->default_service; if (!service) { edje_object_part_text_set(o, "e.text.name", _("No Connection")); edje_object_signal_emit(o, "e,changed,service,none", "e"); edje_object_signal_emit(o, "e,changed,connected,no", "e"); edje_object_part_text_set(o, "e.text.error", _("Not connected")); edje_object_signal_emit(o, "e,changed,error,no", "e"); edje_object_part_text_set(o, "e.text.state", _("disconnect")); edje_object_signal_emit(o, "e,changed,mode,no", "e"); edje_object_signal_emit(o, "e,changed,mode,none", "e"); edje_object_signal_emit(o, "e,changed,security,none", "e"); edje_object_part_text_set(o, "e.text.ipv4_address", ""); edje_object_signal_emit(o, "e,changed,ipv4_address,no", "e"); edje_object_signal_emit(o, "e,changed,favorite,no", "e"); edje_object_signal_emit(o, "e,changed,auto_connect,no", "e"); edje_object_signal_emit(o, "e,changed,pass_required,no", "e"); return; } edje_object_signal_emit(o, "e,changed,connected,yes", "e"); if (service->name) edje_object_part_text_set(o, "e.text.name", service->name); else edje_object_part_text_set(o, "e.text.name", _("Unknown Name")); if (service->error) { edje_object_part_text_set(o, "e.text.error", service->error); edje_object_signal_emit(o, "e,changed,error,yes", "e"); } else { edje_object_part_text_set(o, "e.text.error", _("No error")); edje_object_signal_emit(o, "e,changed,error,no", "e"); } snprintf(buf, sizeof(buf), "e,changed,service,%s", service->type); edje_object_signal_emit(o, buf, "e"); if (!ctxt->technology) { edje_object_part_text_set(o, "e.text.technology", service->type); snprintf(buf, sizeof(buf), "e,changed,technology,%s", service->type); edje_object_signal_emit(o, buf, "e"); } snprintf(buf, sizeof(buf), "e,changed,state,%s", service->state); edje_object_signal_emit(o, buf, "e"); edje_object_part_text_set(o, "e.text.state", _(service->state)); if (service->mode) { snprintf(buf, sizeof(buf), "e,changed,mode,%s", service->mode); edje_object_signal_emit(o, buf, "e"); } else edje_object_signal_emit(o, "e,changed,mode,none", "e"); if (service->security) { snprintf(buf, sizeof(buf), "e,changed,security,%s", service->security); edje_object_signal_emit(o, buf, "e"); } else edje_object_signal_emit(o, "e,changed,security,none", "e"); if (service->ipv4_address) { edje_object_part_text_set(o, "e.text.ipv4_address", service->ipv4_address); edje_object_signal_emit(o, "e,changed,ipv4_address,yes", "e"); } else { edje_object_part_text_set(o, "e.text.ipv4_address", ""); edje_object_signal_emit(o, "e,changed,ipv4_address,no", "e"); } if (service->favorite) edje_object_signal_emit(o, "e,changed,favorite,yes", "e"); else edje_object_signal_emit(o, "e,changed,favorite,no", "e"); if (service->auto_connect) edje_object_signal_emit(o, "e,changed,auto_connect,yes", "e"); else edje_object_signal_emit(o, "e,changed,auto_connect,no", "e"); if (service->pass_required) edje_object_signal_emit(o, "e,changed,pass_required,yes", "e"); else edje_object_signal_emit(o, "e,changed,pass_required,no", "e"); msg.val = service->strength; edje_object_message_send(o, EDJE_MESSAGE_INT, 1, &msg); } static void _connman_tip_update(E_Connman_Instance *inst) { _connman_edje_view_update(inst, inst->o_tip); } static void _connman_gadget_update(E_Connman_Instance *inst) { E_Connman_Module_Context *ctxt = inst->ctxt; if (!ctxt->has_manager && inst->popup) _connman_popup_del(inst); if (inst->popup) _connman_popup_update(inst); if (inst->tip) _connman_tip_update(inst); _connman_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_Connman_Instance *inst; E_Connman_Module_Context *ctxt; if (!connman_mod) return NULL; ctxt = connman_mod->data; inst = E_NEW(E_Connman_Instance, 1); inst->ctxt = ctxt; inst->ui.gadget = edje_object_add(gc->evas); e_theme_edje_object_set(inst->ui.gadget, "base/theme/modules/connman", "e/modules/connman/main"); 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, _connman_cb_mouse_down, inst); evas_object_event_callback_add (inst->ui.gadget, EVAS_CALLBACK_MOUSE_IN, _connman_cb_mouse_in, inst); evas_object_event_callback_add (inst->ui.gadget, EVAS_CALLBACK_MOUSE_OUT, _connman_cb_mouse_out, inst); _connman_gadget_update(inst); ctxt->instances = eina_list_append(ctxt->instances, inst); return inst->gcc; } static void _gc_shutdown(E_Gadcon_Client *gcc) { E_Connman_Module_Context *ctxt; E_Connman_Instance *inst; if (!connman_mod) return; ctxt = connman_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)); } evas_object_del(inst->ui.gadget); 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 _(_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_connman_theme_path(), "icon"); return o; } static const char * _gc_id_new(E_Gadcon_Client_Class *client_class __UNUSED__) { E_Connman_Module_Context *ctxt; Eina_List *instances; if (!connman_mod) return NULL; ctxt = connman_mod->data; if (!ctxt) return NULL; instances = ctxt->instances; snprintf(tmpbuf, sizeof(tmpbuf), "connman.%d", eina_list_count(instances)); return tmpbuf; } static const E_Gadcon_Client_Class _gc_class = { GADCON_CLIENT_CLASS_VERSION, _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, _Name}; static const char _act_toggle_offline_mode[] = "toggle_offline_mode"; static const char _lbl_toggle_offline_mode[] = "Toggle Offline Mode"; static void _connman_actions_register(E_Connman_Module_Context *ctxt) { ctxt->actions.toggle_offline_mode = e_action_add(_act_toggle_offline_mode); if (ctxt->actions.toggle_offline_mode) { ctxt->actions.toggle_offline_mode->func.go = _connman_cb_toggle_offline_mode; e_action_predef_name_set (_(_Name), _(_lbl_toggle_offline_mode), _act_toggle_offline_mode, NULL, NULL, 0); } } static void _connman_actions_unregister(E_Connman_Module_Context *ctxt) { if (ctxt->actions.toggle_offline_mode) { e_action_predef_name_del(_(_Name), _(_lbl_toggle_offline_mode)); e_action_del(_act_toggle_offline_mode); } } static int _connman_manager_changed_do(void *data) { E_Connman_Module_Context *ctxt = data; _connman_services_reload(ctxt); ctxt->poller.manager_changed = NULL; return 0; } static void _connman_manager_changed(void *data, const E_Connman_Element *element __UNUSED__) { E_Connman_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, _connman_manager_changed_do, ctxt); } static int _connman_event_manager_in(void *data, int type __UNUSED__, void *event __UNUSED__) { E_Connman_Module_Context *ctxt = data; E_Connman_Element *element; ctxt->has_manager = EINA_TRUE; element = e_connman_manager_get(); e_connman_element_listener_add (element, _connman_manager_changed, ctxt, NULL); _connman_services_reload(ctxt); return 1; } static int _connman_event_manager_out(void *data, int type __UNUSED__, void *event __UNUSED__) { E_Connman_Module_Context *ctxt = data; ctxt->has_manager = EINA_FALSE; eina_stringshare_replace(&ctxt->technology, NULL); _connman_services_free(ctxt); _connman_default_service_changed(ctxt); return 1; } static int _connman_event_mode_changed(void *data, int type __UNUSED__, void *event __UNUSED__) { E_Connman_Module_Context *ctxt = data; if ((ctxt->offline_mode == e_config->mode.offline) || (!ctxt->has_manager)) return 1; if (!e_connman_manager_offline_mode_set (e_config->mode.offline, _connman_toggle_offline_mode_pending_cb, ctxt)) _connman_operation_error_show (_("Cannot toggle system's offline mode.")); else ctxt->offline_mode_pending = EINA_TRUE; return 1; } static void _connman_events_register(E_Connman_Module_Context *ctxt) { ctxt->event.manager_in = ecore_event_handler_add (E_CONNMAN_EVENT_MANAGER_IN, _connman_event_manager_in, ctxt); ctxt->event.manager_out = ecore_event_handler_add (E_CONNMAN_EVENT_MANAGER_OUT, _connman_event_manager_out, ctxt); ctxt->event.mode_changed = ecore_event_handler_add (E_EVENT_CONFIG_MODE_CHANGED, _connman_event_mode_changed, ctxt); } static void _connman_events_unregister(E_Connman_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.mode_changed) ecore_event_handler_del(ctxt->event.mode_changed); } EAPI void * e_modapi_init(E_Module *m) { E_Connman_Module_Context *ctxt; E_DBus_Connection *c; e_str_idle = eina_stringshare_add(N_("idle")); e_str_association = eina_stringshare_add(N_("association")); e_str_configuration = eina_stringshare_add(N_("configuration")); e_str_ready = eina_stringshare_add(N_("ready")); e_str_disconnect = eina_stringshare_add(N_("disconnect")); e_str_failure = eina_stringshare_add(N_("failure")); c = e_dbus_bus_get(DBUS_BUS_SYSTEM); if (!c) return NULL; if (!e_connman_system_init(c)) return NULL; ctxt = E_NEW(E_Connman_Module_Context, 1); if (!ctxt) return NULL; _connman_actions_register(ctxt); e_gadcon_provider_register(&_gc_class); _connman_events_register(ctxt); connman_mod = m; return ctxt; } static void _connman_instances_free(E_Connman_Module_Context *ctxt) { while (ctxt->instances) { E_Connman_Instance *inst; inst = ctxt->instances->data; if (inst->popup) _connman_popup_del(inst); if (inst->tip) _connman_tip_del(inst); e_object_del(E_OBJECT(inst->gcc)); } } EAPI int e_modapi_shutdown(E_Module *m) { E_Connman_Module_Context *ctxt; E_Connman_Element *element; ctxt = m->data; if (!ctxt) return 0; element = e_connman_manager_get(); e_connman_element_listener_del (element, _connman_manager_changed, ctxt); _connman_events_unregister(ctxt); _connman_instances_free(ctxt); _connman_services_free(ctxt); _connman_actions_unregister(ctxt); e_gadcon_provider_unregister(&_gc_class); if (ctxt->poller.default_service_changed) ecore_poller_del(ctxt->poller.default_service_changed); if (ctxt->poller.manager_changed) ecore_poller_del(ctxt->poller.manager_changed); E_FREE(ctxt); connman_mod = NULL; e_connman_system_shutdown(); eina_stringshare_replace(&e_str_idle, NULL); eina_stringshare_replace(&e_str_association, NULL); eina_stringshare_replace(&e_str_configuration, NULL); eina_stringshare_replace(&e_str_ready, NULL); eina_stringshare_replace(&e_str_disconnect, NULL); eina_stringshare_replace(&e_str_failure, NULL); return 1; } EAPI int e_modapi_save(E_Module *m) { E_Connman_Module_Context *ctxt; ctxt = m->data; if (!ctxt) return 0; return 1; }