This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch network-manager
in repository enlightenment.
View the commit online.
commit 8a29b656dc9e232686b9cb54d1205490638937ce
Author: [email protected] <[email protected]>
AuthorDate: Sat Mar 7 11:26:40 2026 -0700
fix: stabilize NetworkManager D-Bus lifecycle and UI behavior
Replace one-shot D-Bus proxy pattern with persistent signal watchers
for ActiveConnection and IP4Config tracking. The previous approach
created/destroyed proxies on every state change, flooding NM with
match rule churn and causing crashes.
Key changes:
- Persistent PropertiesChanged watchers on ActiveConnection and
IP4Config objects eliminate repeated GetAll polling
- SSID-based deduplication in popup (one entry per network, strongest
signal shown)
- Filter empty/hidden SSIDs from AP list
- Map NM state values to ConnMan theme states for correct icon display
- Add IP address label to popup
- Use SSID-based matching for active network detection (handles
multi-station roaming)
- Fix ilist selection callback loop that caused connect/disconnect
thrashing
Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
src/modules/networkmanager/e_mod_main.c | 157 +++++++++++-----
src/modules/networkmanager/e_mod_main.h | 1 +
src/modules/networkmanager/e_networkmanager.c | 259 ++++++++++++++++++++------
src/modules/networkmanager/e_networkmanager.h | 11 ++
4 files changed, 324 insertions(+), 104 deletions(-)
diff --git a/src/modules/networkmanager/e_mod_main.c b/src/modules/networkmanager/e_mod_main.c
index 28873f4a6..3cc958f4b 100644
--- a/src/modules/networkmanager/e_mod_main.c
+++ b/src/modules/networkmanager/e_mod_main.c
@@ -32,7 +32,7 @@ void
enm_popup_del(E_NM_Instance *inst)
{
E_FREE_FUNC(inst->popup, e_object_del);
- inst->ui.popup.enabled = inst->ui.popup.list = NULL;
+ inst->ui.popup.enabled = inst->ui.popup.list = inst->ui.popup.ip_label = NULL;
}
static void
@@ -61,6 +61,8 @@ _enm_wireless_changed(void *data, Evas_Object *obj EINA_UNUSED,
enm_wireless_enabled_set(ctxt->nm, !!ctxt->wireless_enabled);
}
+static Eina_Bool _enm_ssid_is_active(struct NM_Manager *nm, const char *ssid);
+
static void
_enm_popup_selected_cb(void *data)
{
@@ -80,7 +82,7 @@ _enm_popup_selected_cb(void *data)
if (!ap) return;
/* If this AP is currently active, disconnect instead */
- if (nm->active_ap_path && (nm->active_ap_path == ap->path))
+ if (nm->active_ap_path && _enm_ssid_is_active(nm, ap->ssid))
{
INF("Disconnect from %s", ap->ssid ?: path);
enm_ap_disconnect(nm);
@@ -118,7 +120,7 @@ _enm_ap_icon_new(struct NM_Manager *nm, struct NM_Access_Point *ap, Evas *evas)
"e/modules/connman/icon/wifi");
/* Map active AP to ONLINE(5), otherwise IDLE(1) — ConnMan theme values */
- state_val = (nm->active_ap_path && nm->active_ap_path == ap->path) ? 5 : 1;
+ state_val = (ap->ssid && _enm_ssid_is_active(nm, ap->ssid)) ? 5 : 1;
msg = malloc(sizeof(*msg) + sizeof(int));
if (msg)
@@ -163,6 +165,45 @@ _enm_ap_end_new(struct NM_Access_Point *ap, Evas *evas)
return end;
}
+/* Find the best AP for a given SSID across all devices.
+ * Prefers the active AP if it matches, otherwise picks highest strength.
+ * Used to deduplicate multiple stations broadcasting the same network name. */
+static struct NM_Access_Point *
+_enm_best_ap_for_ssid(struct NM_Manager *nm, const char *ssid)
+{
+ struct NM_Device *dev;
+ struct NM_Access_Point *best = NULL;
+
+ EINA_INLIST_FOREACH(nm->devices, dev)
+ {
+ struct NM_Access_Point *ap;
+ if (dev->type != NM_DEVICE_TYPE_WIFI) continue;
+ EINA_INLIST_FOREACH(dev->access_points, ap)
+ {
+ if (!ap->ssid || !ap->ssid[0]) continue;
+ if (strcmp(ap->ssid, ssid)) continue;
+ /* Always prefer the active AP */
+ if (nm->active_ap_path && nm->active_ap_path == ap->path)
+ return ap;
+ if (!best || ap->strength > best->strength)
+ best = ap;
+ }
+ }
+ return best;
+}
+
+/* Check if the given SSID matches the currently connected network */
+static Eina_Bool
+_enm_ssid_is_active(struct NM_Manager *nm, const char *ssid)
+{
+ struct NM_Access_Point *active;
+
+ if (!nm->active_ap_path) return EINA_FALSE;
+ active = enm_manager_find_ap(nm, nm->active_ap_path);
+ if (!active || !active->ssid) return EINA_FALSE;
+ return !strcmp(active->ssid, ssid);
+}
+
static void
_enm_popup_update(struct NM_Manager *nm, E_NM_Instance *inst)
{
@@ -170,13 +211,17 @@ _enm_popup_update(struct NM_Manager *nm, E_NM_Instance *inst)
Evas_Object *enabled = inst->ui.popup.enabled;
Evas *evas = evas_object_evas_get(list);
struct NM_Device *dev;
- const char *hidden = "«hidden»";
+ Eina_Hash *seen_ssids;
EINA_SAFETY_ON_NULL_RETURN(nm);
e_widget_ilist_freeze(list);
e_widget_ilist_clear(list);
+ /* Deduplicate APs by SSID — show only the strongest station per SSID */
+ seen_ssids = eina_hash_string_superfast_new(NULL);
+
+
EINA_INLIST_FOREACH(nm->devices, dev)
{
struct NM_Access_Point *ap;
@@ -185,24 +230,52 @@ _enm_popup_update(struct NM_Manager *nm, E_NM_Instance *inst)
EINA_INLIST_FOREACH(dev->access_points, ap)
{
- Evas_Object *icon = _enm_ap_icon_new(nm, ap, evas);
- Evas_Object *end = _enm_ap_end_new(ap, evas);
+ struct NM_Access_Point *best;
+ Evas_Object *icon, *end;
+
+ /* Skip hidden networks (empty or NULL SSID) */
+ if (!ap->ssid || !ap->ssid[0]) continue;
+
+ /* Skip if we already showed this SSID */
+ if (eina_hash_find(seen_ssids, ap->ssid)) continue;
+
+ /* Find the best AP for this SSID and only show that one */
+ best = _enm_best_ap_for_ssid(nm, ap->ssid);
+ if (!best) continue;
+
+ eina_hash_add(seen_ssids, ap->ssid, (void *)1);
+
+ icon = _enm_ap_icon_new(nm, best, evas);
+ end = _enm_ap_end_new(best, evas);
e_widget_ilist_append_full(list, icon, end,
- ap->ssid ?: hidden,
+ best->ssid,
_enm_popup_selected_cb,
- inst, ap->path);
+ inst, best->path);
}
}
+ eina_hash_free(seen_ssids);
+
e_widget_ilist_thaw(list);
e_widget_ilist_go(list);
+ /* Update IP label */
+ if (nm->ip_address)
+ {
+ char ipbuf[128];
+ snprintf(ipbuf, sizeof(ipbuf), "IP: %s", nm->ip_address);
+ e_widget_label_text_set(inst->ui.popup.ip_label, ipbuf);
+ }
+ else
+ e_widget_label_text_set(inst->ui.popup.ip_label, "");
+
if (inst->ctxt)
{
inst->ctxt->wireless_enabled = nm->wireless_enabled ? 1 : 0;
e_widget_check_checked_set(enabled, inst->ctxt->wireless_enabled);
}
+
}
static void
@@ -254,6 +327,9 @@ _enm_popup_new(E_NM_Instance *inst)
e_widget_size_min_set(inst->ui.popup.list, 60, 100);
e_widget_list_object_append(list, inst->ui.popup.list, 1, 1, 0.5);
+ inst->ui.popup.ip_label = e_widget_label_add(evas, "");
+ e_widget_list_object_append(list, inst->ui.popup.ip_label, 1, 0, 0.5);
+
ck = e_widget_check_add(evas, _("Wifi On"), &(ctxt->wireless_enabled));
inst->ui.popup.enabled = ck;
e_widget_list_object_append(list, ck, 1, 0, 0.5);
@@ -304,6 +380,25 @@ _enm_gadget_setup(E_NM_Instance *inst)
edje_object_signal_emit(o, "e,available", "e");
}
+/* Map NM state to ConnMan theme state values:
+ * OFFLINE=0, IDLE=1, ASSOCIATION=2, CONFIGURATION=3, READY=4, _ONLINE_=5 */
+static int
+_enm_state_to_connman(enum NM_State state)
+{
+ switch (state)
+ {
+ case NM_STATE_UNKNOWN:
+ case NM_STATE_ASLEEP: return 0; /* OFFLINE */
+ case NM_STATE_DISCONNECTED:
+ case NM_STATE_DISCONNECTING: return 1; /* IDLE */
+ case NM_STATE_CONNECTING: return 2; /* ASSOCIATION */
+ case NM_STATE_CONNECTED_LOCAL: return 4; /* READY */
+ case NM_STATE_CONNECTED_SITE: return 4; /* READY */
+ case NM_STATE_CONNECTED_GLOBAL: return 5; /* ONLINE */
+ default: return 0;
+ }
+}
+
static void
_enm_mod_manager_update_inst(E_NM_Module_Context *ctxt EINA_UNUSED,
E_NM_Instance *inst,
@@ -315,19 +410,20 @@ _enm_mod_manager_update_inst(E_NM_Module_Context *ctxt EINA_UNUSED,
struct NM_Access_Point *active_ap = NULL;
const char *typestr = "wifi";
char buf[256];
- char tooltip[256];
uint8_t strength;
+ int theme_state;
/* Resolve active AP for real signal strength */
if (nm && nm->active_ap_path)
active_ap = enm_manager_find_ap(nm, nm->active_ap_path);
strength = active_ap ? active_ap->strength : 0;
+ theme_state = _enm_state_to_connman(state);
msg = malloc(sizeof(*msg) + sizeof(int));
if (!msg) return;
msg->count = 2;
- msg->val[0] = state;
+ msg->val[0] = theme_state;
msg->val[1] = strength;
edje_object_message_send(o, EDJE_MESSAGE_INT_SET, 1, msg);
@@ -336,43 +432,10 @@ _enm_mod_manager_update_inst(E_NM_Module_Context *ctxt EINA_UNUSED,
snprintf(buf, sizeof(buf), "e,changed,technology,%s", typestr);
edje_object_signal_emit(o, buf, "e");
- /* Build tooltip text for the gadget label */
- if (!nm)
- snprintf(tooltip, sizeof(tooltip), _("NetworkManager unavailable"));
- else if (state == NM_STATE_CONNECTED_GLOBAL ||
- state == NM_STATE_CONNECTED_SITE ||
- state == NM_STATE_CONNECTED_LOCAL)
- {
- const char *ssid = active_ap ? active_ap->ssid : NULL;
- const char *ip = nm->ip_address;
-
- if (ssid && ip)
- snprintf(tooltip, sizeof(tooltip), _("WiFi: %s — %s"), ssid, ip);
- else if (ssid)
- snprintf(tooltip, sizeof(tooltip), _("WiFi: %s"), ssid);
- else if (ip)
- snprintf(tooltip, sizeof(tooltip), _("Connected — %s"), ip);
- else
- snprintf(tooltip, sizeof(tooltip), _("Connected"));
- }
- else if (state == NM_STATE_CONNECTING)
- {
- const char *ssid = active_ap ? active_ap->ssid : NULL;
- if (ssid)
- snprintf(tooltip, sizeof(tooltip), _("Connecting: %s"), ssid);
- else
- snprintf(tooltip, sizeof(tooltip), _("Connecting…"));
- }
- else if (state == NM_STATE_DISCONNECTED ||
- state == NM_STATE_DISCONNECTING)
- snprintf(tooltip, sizeof(tooltip), _("Disconnected"));
- else
- snprintf(tooltip, sizeof(tooltip), _("NetworkManager: %s"),
- enm_state_to_str(state));
-
- edje_object_part_text_set(o, "e.text.label", tooltip);
-
- DBG("state=%d strength=%u tooltip='%s'", state, strength, tooltip);
+ DBG("state=%d (theme=%d) strength=%u active_ap=%s ip=%s",
+ state, theme_state, strength,
+ nm ? (nm->active_ap_path ?: "(null)") : "no-nm",
+ nm ? (nm->ip_address ?: "(null)") : "no-nm");
}
void
diff --git a/src/modules/networkmanager/e_mod_main.h b/src/modules/networkmanager/e_mod_main.h
index 346144475..d8166e186 100644
--- a/src/modules/networkmanager/e_mod_main.h
+++ b/src/modules/networkmanager/e_mod_main.h
@@ -27,6 +27,7 @@ struct E_NM_Instance
struct
{
Evas_Object *list;
+ Evas_Object *ip_label;
Evas_Object *enabled; /* "Wifi On" checkbox */
} popup;
} ui;
diff --git a/src/modules/networkmanager/e_networkmanager.c b/src/modules/networkmanager/e_networkmanager.c
index 64b61b76d..4a6bc5dc7 100644
--- a/src/modules/networkmanager/e_networkmanager.c
+++ b/src/modules/networkmanager/e_networkmanager.c
@@ -516,9 +516,87 @@ _device_free(struct NM_Device *dev)
}
/* -------------------------------------------------------------------------- */
-/* IP tracking */
+/* IP tracking (persistent watcher) */
/* -------------------------------------------------------------------------- */
+static void
+_manager_ip4_watch_free(struct NM_Manager *nm)
+{
+ if (nm->pending.ip4config)
+ {
+ eldbus_pending_cancel(nm->pending.ip4config);
+ nm->pending.ip4config = NULL;
+ }
+ if (nm->ip4_proxy)
+ {
+ eldbus_proxy_unref(nm->ip4_proxy);
+ eldbus_object_unref(nm->ip4_obj);
+ nm->ip4_proxy = NULL;
+ nm->ip4_obj = NULL;
+ }
+ eina_stringshare_del(nm->ip4_path);
+ nm->ip4_path = NULL;
+}
+
+/* Parse AddressData from a variant containing aa{sv} */
+static void
+_ip4_parse_address_data(struct NM_Manager *nm, Eldbus_Message_Iter *var)
+{
+ Eldbus_Message_Iter *addr_array, *addr_dict, *entry;
+ const char *entry_key;
+ Eldbus_Message_Iter *entry_var;
+
+ if (!eldbus_message_iter_arguments_get(var, "aa{sv}", &addr_array))
+ return;
+
+ /* Take the first address */
+ if (!eldbus_message_iter_get_and_next(addr_array, 'a', &addr_dict))
+ return;
+
+ while (eldbus_message_iter_get_and_next(addr_dict, 'e', &entry))
+ {
+ if (!eldbus_message_iter_arguments_get(entry, "sv",
+ &entry_key, &entry_var))
+ continue;
+ if (!strcmp(entry_key, "address"))
+ {
+ const char *addr;
+ if (eldbus_message_iter_arguments_get(entry_var, "s", &addr))
+ {
+ free(nm->ip_address);
+ nm->ip_address = strdup(addr);
+ DBG("IP address: %s", nm->ip_address);
+ }
+ }
+ }
+}
+
+static void
+_ip4_prop_changed(void *data, const Eldbus_Message *msg)
+{
+ struct NM_Manager *nm = data;
+ Eldbus_Message_Iter *changed_props, *invalidated;
+ const char *iface;
+ Eldbus_Message_Iter *dict, *var;
+ const char *key;
+
+ if (!eldbus_message_arguments_get(msg, "sa{sv}as",
+ &iface, &changed_props, &invalidated))
+ return;
+
+ while (eldbus_message_iter_get_and_next(changed_props, 'e', &dict))
+ {
+ if (!eldbus_message_iter_arguments_get(dict, "sv", &key, &var))
+ continue;
+
+ if (!strcmp(key, "AddressData"))
+ {
+ _ip4_parse_address_data(nm, var);
+ enm_mod_manager_update(nm);
+ }
+ }
+}
+
static void
_ip4config_get_props_cb(void *data, const Eldbus_Message *msg,
Eldbus_Pending *pending EINA_UNUSED)
@@ -547,67 +625,105 @@ _ip4config_get_props_cb(void *data, const Eldbus_Message *msg,
continue;
if (!strcmp(key, "AddressData"))
- {
- Eldbus_Message_Iter *addr_array, *addr_dict, *entry;
- const char *entry_key;
- Eldbus_Message_Iter *entry_var;
-
- if (!eldbus_message_iter_arguments_get(var, "aa{sv}", &addr_array))
- continue;
-
- /* Take the first address */
- if (!eldbus_message_iter_get_and_next(addr_array, 'a', &addr_dict))
- continue;
-
- while (eldbus_message_iter_get_and_next(addr_dict, 'e', &entry))
- {
- if (!eldbus_message_iter_arguments_get(entry, "sv",
- &entry_key,
- &entry_var))
- continue;
- if (!strcmp(entry_key, "address"))
- {
- const char *addr;
- if (eldbus_message_iter_arguments_get(entry_var, "s",
- &addr))
- {
- free(nm->ip_address);
- nm->ip_address = strdup(addr);
- DBG("IP address: %s", nm->ip_address);
- }
- }
- }
- }
+ _ip4_parse_address_data(nm, var);
}
+
+ /* Proxy stays alive — updates arrive via _ip4_prop_changed signal */
+ enm_mod_manager_update(nm);
}
static void
-_manager_fetch_ip(struct NM_Manager *nm, const char *ip4config_path)
+_manager_watch_ip4(struct NM_Manager *nm, const char *ip4config_path)
{
Eldbus_Object *obj;
Eldbus_Proxy *props;
if (!ip4config_path || !strcmp(ip4config_path, "/")) return;
- if (nm->pending.ip4config)
- eldbus_pending_cancel(nm->pending.ip4config);
+ /* Skip if already watching this exact path */
+ if (nm->ip4_path && !strcmp(nm->ip4_path, ip4config_path))
+ return;
+
+ /* Tear down previous watcher */
+ _manager_ip4_watch_free(nm);
obj = eldbus_object_get(conn, NM_BUS_NAME, ip4config_path);
props = eldbus_proxy_get(obj, NM_IFACE_PROPS);
+ nm->ip4_proxy = props;
+ nm->ip4_obj = obj;
+ nm->ip4_path = eina_stringshare_add(ip4config_path);
+
+ /* Subscribe to property changes — keeps proxy alive for signals */
+ eldbus_proxy_signal_handler_add(props, "PropertiesChanged",
+ _ip4_prop_changed, nm);
+
+ /* Initial fetch */
nm->pending.ip4config = eldbus_proxy_call(props, "GetAll",
_ip4config_get_props_cb, nm,
-1, "s", NM_IFACE_IP4);
-
- /* Unref proxy/obj; the pending keeps them alive until callback fires */
- eldbus_proxy_unref(props);
- eldbus_object_unref(obj);
}
/* -------------------------------------------------------------------------- */
-/* Active connection tracking */
+/* Active connection tracking (persistent watcher) */
/* -------------------------------------------------------------------------- */
+static void
+_manager_active_conn_watch_free(struct NM_Manager *nm)
+{
+ if (nm->pending.active_conn)
+ {
+ eldbus_pending_cancel(nm->pending.active_conn);
+ nm->pending.active_conn = NULL;
+ }
+ if (nm->active_conn_proxy)
+ {
+ eldbus_proxy_unref(nm->active_conn_proxy);
+ eldbus_object_unref(nm->active_conn_obj);
+ nm->active_conn_proxy = NULL;
+ nm->active_conn_obj = NULL;
+ }
+}
+
+static void
+_active_conn_prop_changed(void *data, const Eldbus_Message *msg)
+{
+ struct NM_Manager *nm = data;
+ Eldbus_Message_Iter *changed_props, *invalidated;
+ const char *iface;
+ Eldbus_Message_Iter *dict, *var;
+ const char *key;
+
+ if (!eldbus_message_arguments_get(msg, "sa{sv}as",
+ &iface, &changed_props, &invalidated))
+ return;
+
+ while (eldbus_message_iter_get_and_next(changed_props, 'e', &dict))
+ {
+ if (!eldbus_message_iter_arguments_get(dict, "sv", &key, &var))
+ continue;
+
+ if (!strcmp(key, "Ip4Config"))
+ {
+ const char *ip4path;
+ if (eldbus_message_iter_arguments_get(var, "o", &ip4path))
+ _manager_watch_ip4(nm, ip4path);
+ }
+ else if (!strcmp(key, "SpecificObject"))
+ {
+ const char *ap_path;
+ if (eldbus_message_iter_arguments_get(var, "o", &ap_path))
+ {
+ DBG("ActiveConn SpecificObject changed: %s", ap_path);
+ eina_stringshare_del(nm->active_ap_path);
+ nm->active_ap_path = eina_stringshare_add(ap_path);
+ enm_mod_manager_update(nm);
+ enm_mod_aps_changed(nm);
+ }
+ }
+ }
+}
+
static void
_active_conn_get_props_cb(void *data, const Eldbus_Message *msg,
Eldbus_Pending *pending EINA_UNUSED)
@@ -625,7 +741,10 @@ _active_conn_get_props_cb(void *data, const Eldbus_Message *msg,
}
if (!eldbus_message_arguments_get(msg, "a{sv}", &array))
- return;
+ {
+ WRN("ActiveConnection GetAll: cannot parse a{sv}");
+ return;
+ }
while (eldbus_message_iter_get_and_next(array, 'e', &dict))
{
@@ -639,45 +758,62 @@ _active_conn_get_props_cb(void *data, const Eldbus_Message *msg,
{
const char *ip4path;
if (eldbus_message_iter_arguments_get(var, "o", &ip4path))
- _manager_fetch_ip(nm, ip4path);
+ _manager_watch_ip4(nm, ip4path);
}
else if (!strcmp(key, "SpecificObject"))
{
- /* AP path for the active WiFi connection */
const char *ap_path;
if (eldbus_message_iter_arguments_get(var, "o", &ap_path))
{
+ DBG("ActiveConn SpecificObject=%s", ap_path);
eina_stringshare_del(nm->active_ap_path);
nm->active_ap_path = eina_stringshare_add(ap_path);
}
}
}
+
+ /* Proxy stays alive — updates arrive via _active_conn_prop_changed */
+ DBG("ActiveConn done: active_ap=%s", nm->active_ap_path ?: "(null)");
+ enm_mod_manager_update(nm);
+ enm_mod_aps_changed(nm);
}
static void
-_manager_check_active_connections(struct NM_Manager *nm,
- const char *active_conn_path)
+_manager_watch_active_conn(struct NM_Manager *nm,
+ const char *active_conn_path)
{
Eldbus_Object *obj;
Eldbus_Proxy *props;
+ DBG("_manager_watch_active_conn path=%s", active_conn_path ?: "(null)");
if (!active_conn_path || !strcmp(active_conn_path, "/")) return;
+ /* Skip if already watching this exact connection */
+ if (nm->active_connection_path &&
+ !strcmp(nm->active_connection_path, active_conn_path))
+ return;
+
eina_stringshare_del(nm->active_connection_path);
nm->active_connection_path = eina_stringshare_add(active_conn_path);
- if (nm->pending.active_conn)
- eldbus_pending_cancel(nm->pending.active_conn);
+ /* Tear down previous watchers (active conn + ip4) */
+ _manager_active_conn_watch_free(nm);
+ _manager_ip4_watch_free(nm);
obj = eldbus_object_get(conn, NM_BUS_NAME, active_conn_path);
props = eldbus_proxy_get(obj, NM_IFACE_PROPS);
+ nm->active_conn_proxy = props;
+ nm->active_conn_obj = obj;
+
+ /* Subscribe to property changes — keeps proxy alive for signals */
+ eldbus_proxy_signal_handler_add(props, "PropertiesChanged",
+ _active_conn_prop_changed, nm);
+
+ /* Initial fetch */
nm->pending.active_conn = eldbus_proxy_call(props, "GetAll",
_active_conn_get_props_cb, nm,
-1, "s", NM_IFACE_ACONN);
-
- eldbus_proxy_unref(props);
- eldbus_object_unref(obj);
}
/* -------------------------------------------------------------------------- */
@@ -736,9 +872,12 @@ _manager_prop_changed(void *data, const Eldbus_Message *msg)
/* Use first active connection */
if (eldbus_message_iter_get_and_next(conn_array, 'o', &aconn_path))
- _manager_check_active_connections(nm, aconn_path);
+ _manager_watch_active_conn(nm, aconn_path);
else
{
+ /* No active connections — tear down watchers */
+ _manager_active_conn_watch_free(nm);
+ _manager_ip4_watch_free(nm);
eina_stringshare_del(nm->active_ap_path);
nm->active_ap_path = NULL;
eina_stringshare_del(nm->active_connection_path);
@@ -799,12 +938,19 @@ _manager_get_props_cb(void *data, const Eldbus_Message *msg,
const char *aconn_path;
if (!eldbus_message_iter_arguments_get(var, "ao", &conn_array))
- continue;
+ {
+ WRN("ActiveConnections: cannot parse ao from variant");
+ continue;
+ }
if (eldbus_message_iter_get_and_next(conn_array, 'o', &aconn_path))
- _manager_check_active_connections(nm, aconn_path);
+ {
+ DBG("ActiveConnections: first path=%s", aconn_path);
+ _manager_watch_active_conn(nm, aconn_path);
+ }
else
{
+ DBG("ActiveConnections: empty array");
eina_stringshare_del(nm->active_ap_path);
nm->active_ap_path = NULL;
eina_stringshare_del(nm->active_connection_path);
@@ -947,10 +1093,9 @@ _manager_free(struct NM_Manager *nm)
eldbus_pending_cancel(nm->pending.get_props);
if (nm->pending.get_devices)
eldbus_pending_cancel(nm->pending.get_devices);
- if (nm->pending.active_conn)
- eldbus_pending_cancel(nm->pending.active_conn);
- if (nm->pending.ip4config)
- eldbus_pending_cancel(nm->pending.ip4config);
+
+ _manager_active_conn_watch_free(nm);
+ _manager_ip4_watch_free(nm);
while (nm->devices)
{
diff --git a/src/modules/networkmanager/e_networkmanager.h b/src/modules/networkmanager/e_networkmanager.h
index 38d6e0e02..1f8e6ac90 100644
--- a/src/modules/networkmanager/e_networkmanager.h
+++ b/src/modules/networkmanager/e_networkmanager.h
@@ -106,6 +106,17 @@ struct NM_Manager
Eldbus_Pending *active_conn;
Eldbus_Pending *ip4config;
} pending;
+
+ /* Persistent proxy/obj for watching active connection properties.
+ * Created when active connection changes, freed when it changes again
+ * or on manager shutdown. Signal-driven via PropertiesChanged. */
+ Eldbus_Proxy *active_conn_proxy;
+ Eldbus_Object *active_conn_obj;
+
+ /* Persistent proxy/obj for watching IP4Config properties. */
+ Eldbus_Proxy *ip4_proxy;
+ Eldbus_Object *ip4_obj;
+ const char *ip4_path;
};
/* Ecore Events */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.