This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository enlightenment.
View the commit online.
commit 0da482d3eaf549f18f1a665ff1d67fcda43fd895
Author: [email protected] <[email protected]>
AuthorDate: Wed Apr 15 10:45:48 2026 -0600
refactor(networkmanager): modernize password dialog and IP label to Elementary
Replace legacy e_widget_* usage with Elementary widgets in the password dialog
and IP label. The password dialog now uses elm_frame/elm_box/elm_entry/elm_check
with direct PSK storage, eliminating toolbook/framelist/list scaffolding.
Fixes markup-to-UTF8 conversion for PSKs containing '<' or '&' by using
elm_entry_markup_to_utf8() on the entry content before sending to NM. Simplifies
the entry "activated" callback to avoid double-submit UAF by listening only
for Escape in the key-down handler. The IP label migrates from e_widget_label
to elm_label with explicit size hints.
Module now has zero e_widget_* references and builds with zero warnings.
Addresses raster's review feedback from PR #125.
Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
---
src/modules/networkmanager/agent.c | 229 +++++++++++++-------------------
src/modules/networkmanager/e_mod_main.c | 13 +-
2 files changed, 98 insertions(+), 144 deletions(-)
diff --git a/src/modules/networkmanager/agent.c b/src/modules/networkmanager/agent.c
index 3ac69dfc3..50cd9f5f8 100644
--- a/src/modules/networkmanager/agent.c
+++ b/src/modules/networkmanager/agent.c
@@ -17,23 +17,18 @@
* is the user-facing dialog that pops when NM asks for a WiFi password, and
* nothing more. The bridge between the two layers is the pair of callbacks
* registered via e_nm_agent_callbacks_set() from enm_agent_ui_register().
+ *
+ * Widgets are Elementary — elm_frame / elm_box / elm_entry / elm_check —
+ * with no legacy e_widget_* dependencies.
*/
-/* One input field rendered inside the password page */
-typedef struct _E_NM_Agent_Input E_NM_Agent_Input;
-struct _E_NM_Agent_Input
-{
- char *key;
- char *value;
- int show_password;
-};
-
-/* State for one live dialog. Owned by the dialog; freed in the del cb. */
+/* State for one live dialog. Freed in the dialog del callback. */
typedef struct _E_NM_Agent_Dialog E_NM_Agent_Dialog;
struct _E_NM_Agent_Dialog
{
E_Dialog *dialog;
- E_NM_Agent_Request *req; /* borrowed pointer — NULL after reply/cancel */
+ Evas_Object *entry; /* elm_entry holding the PSK */
+ E_NM_Agent_Request *req; /* borrowed; NULL once reply/cancel sent */
};
static E_NM_Agent_Dialog *_current_dialog = NULL;
@@ -42,50 +37,45 @@ static E_NM_Agent_Dialog *_current_dialog = NULL;
/* Dialog callbacks */
/* -------------------------------------------------------------------------- */
-static const char *
-_dialog_first_psk(E_Dialog *dialog)
-{
- Evas_Object *toolbook, *list;
- Eina_List *input_list;
- E_NM_Agent_Input *input;
-
- toolbook = dialog->content_object;
- list = evas_object_data_get(toolbook, "psk");
- if (!list) list = evas_object_data_get(toolbook, "password");
- if (!list) return NULL;
-
- input_list = evas_object_data_get(list, "input_list");
- if (!input_list) return NULL;
- input = eina_list_data_get(input_list);
- return input ? input->value : NULL;
-}
-
static void
-_dialog_ok_cb(void *data, E_Dialog *dialog)
+_dialog_send_ok(E_NM_Agent_Dialog *ad)
{
- E_NM_Agent_Dialog *ad = data;
- const char *psk;
+ char *psk = NULL;
+
+ /* elm_entry stores markup internally; convert to plain UTF-8 so that
+ * passwords containing '<' or '&' survive the round-trip to NM. */
+ psk = elm_entry_markup_to_utf8(elm_entry_entry_get(ad->entry));
- psk = _dialog_first_psk(dialog);
if (ad->req)
{
e_nm_agent_reply_secrets(ad->req, psk);
ad->req = NULL;
}
- e_object_del(E_OBJECT(dialog));
+ free(psk);
+ e_object_del(E_OBJECT(ad->dialog));
}
static void
-_dialog_cancel_cb(void *data, E_Dialog *dialog)
+_dialog_send_cancel(E_NM_Agent_Dialog *ad)
{
- E_NM_Agent_Dialog *ad = data;
-
if (ad->req)
{
e_nm_agent_reply_cancel(ad->req);
ad->req = NULL;
}
- e_object_del(E_OBJECT(dialog));
+ e_object_del(E_OBJECT(ad->dialog));
+}
+
+static void
+_dialog_ok_cb(void *data, E_Dialog *dialog EINA_UNUSED)
+{
+ _dialog_send_ok(data);
+}
+
+static void
+_dialog_cancel_cb(void *data, E_Dialog *dialog EINA_UNUSED)
+{
+ _dialog_send_cancel(data);
}
static void
@@ -95,10 +85,19 @@ _dialog_key_down_cb(void *data, Evas *e EINA_UNUSED,
Evas_Event_Key_Down *ev = event;
E_NM_Agent_Dialog *ad = data;
- if (!strcmp(ev->key, "Return"))
- _dialog_ok_cb(ad, ad->dialog);
- else if (!strcmp(ev->key, "Escape"))
- _dialog_cancel_cb(ad, ad->dialog);
+ /* Enter is handled by the entry's "activated" callback so we do not
+ * ACK it here — doing both would run _dialog_send_ok twice on an
+ * already-deleted dialog. Escape always cancels regardless of focus. */
+ if (!strcmp(ev->key, "Escape"))
+ _dialog_send_cancel(ad);
+}
+
+static void
+_entry_activated_cb(void *data, Evas_Object *obj EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ /* Enter key inside the entry triggers Connect */
+ _dialog_send_ok(data);
}
static void
@@ -107,8 +106,10 @@ _dialog_del_cb(void *data)
E_Dialog *dialog = data;
E_NM_Agent_Dialog *ad = e_object_data_get(E_OBJECT(dialog));
- /* If the dialog was closed via the WM (not via OK/Cancel buttons) the
- * request is still live — treat as user cancel. */
+ if (!ad) return;
+
+ /* If the dialog was closed via the WM (not OK/Cancel) the request is
+ * still live — treat as user cancel. */
if (ad->req)
{
e_nm_agent_reply_cancel(ad->req);
@@ -118,101 +119,24 @@ _dialog_del_cb(void *data)
free(ad);
}
-static void
-_page_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED,
- Evas_Object *obj, void *event_info EINA_UNUSED)
-{
- E_NM_Agent_Input *input;
- Eina_List *input_list;
-
- input_list = evas_object_data_get(obj, "input_list");
- EINA_LIST_FREE(input_list, input)
- {
- free(input->key);
- /* input->value is NOT freed here: it is a pointer into the EFL entry
- * widget's internal buffer (set via e_widget_entry_add's &value
- * parameter). The widget owns the allocation; freeing it here would
- * be a double-free once the widget itself is destroyed. */
- free(input);
- }
-}
-
static void
_show_password_cb(void *data, Evas_Object *obj, void *event EINA_UNUSED)
{
Evas_Object *entry = data;
- int hidden;
-
- hidden = !e_widget_check_checked_get(obj);
- e_widget_entry_password_set(entry, hidden);
+ elm_entry_password_set(entry, !elm_check_state_get(obj));
}
/* -------------------------------------------------------------------------- */
/* Dialog construction */
/* -------------------------------------------------------------------------- */
-static void
-_dialog_psk_add(E_Dialog *dialog, const char *ssid)
-{
- Evas_Object *toolbook, *list, *framelist, *entry, *check;
- E_NM_Agent_Input *input;
- Eina_List *input_list;
- char header[128];
- Evas *evas;
-
- evas = evas_object_evas_get(dialog->win);
- toolbook = dialog->content_object;
-
- input = E_NEW(E_NM_Agent_Input, 1);
- input->key = strdup("psk");
- entry = e_widget_entry_add(dialog->win, &(input->value),
- NULL, NULL, NULL);
- evas_object_show(entry);
- e_widget_entry_password_set(entry, 1);
-
- list = evas_object_data_get(toolbook, "psk");
- if (!list)
- {
- list = e_widget_list_add(evas, 0, 0);
- e_widget_toolbook_page_append(toolbook, NULL,
- _("WiFi Password"),
- list, 1, 1, 1, 1, 0.5, 0.0);
- evas_object_data_set(toolbook, "psk", list);
- e_widget_toolbook_page_show(toolbook, 0);
- evas_object_event_callback_add(list, EVAS_CALLBACK_DEL,
- _page_del, NULL);
- e_widget_focus_set(entry, 1);
- }
-
- input_list = evas_object_data_get(list, "input_list");
- input_list = eina_list_append(input_list, input);
- evas_object_data_set(list, "input_list", input_list);
-
- snprintf(header, sizeof(header),
- _("Password required for \"%s\":"), ssid ?: "network");
-
- framelist = e_widget_framelist_add(evas, header, 0);
- evas_object_show(framelist);
- e_widget_list_object_append(list, framelist, 1, 1, 0.5);
- e_widget_framelist_object_append(framelist, entry);
-
- check = e_widget_check_add(evas, _("Show password"),
- &(input->show_password));
- evas_object_show(check);
- e_widget_framelist_object_append(framelist, check);
- evas_object_smart_callback_add(check, "changed",
- _show_password_cb, entry);
-
- e_util_win_auto_resize_fill(dialog->win);
-}
-
static E_NM_Agent_Dialog *
_dialog_new(E_NM_Agent_Request *req, const char *ssid)
{
E_NM_Agent_Dialog *ad;
- Evas_Object *toolbook;
+ Evas_Object *frame, *box, *entry, *check;
E_Dialog *dialog;
- int mw, mh;
+ char header[128];
dialog = e_dialog_new(NULL, "E", "nm_secret_agent");
if (!dialog) return NULL;
@@ -228,26 +152,54 @@ _dialog_new(E_NM_Agent_Request *req, const char *ssid)
e_dialog_button_add(dialog, _("Connect"), NULL, _dialog_ok_cb, ad);
e_dialog_button_add(dialog, _("Cancel"), NULL, _dialog_cancel_cb, ad);
- toolbook = e_widget_toolbook_add(
- evas_object_evas_get(dialog->win),
- 48 * e_scale, 48 * e_scale);
- evas_object_show(toolbook);
+ /* Labelled frame containing the password row + show-password check */
+ snprintf(header, sizeof(header),
+ _("Password required for \"%s\":"), ssid ?: "network");
+ frame = elm_frame_add(dialog->win);
+ elm_object_text_set(frame, header);
+ evas_object_size_hint_weight_set(frame, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
- e_widget_size_min_get(toolbook, &mw, &mh);
- if (mw < 280) mw = 280;
- if (mh < 140) mh = 140;
- e_dialog_content_set(dialog, toolbook, mw, mh);
+ box = elm_box_add(frame);
+ elm_box_horizontal_set(box, EINA_FALSE);
+ elm_box_padding_set(box, 0, 4 * e_scale);
+ evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_object_content_set(frame, box);
+ evas_object_show(box);
+
+ entry = elm_entry_add(box);
+ elm_entry_single_line_set(entry, EINA_TRUE);
+ elm_entry_scrollable_set(entry, EINA_TRUE);
+ elm_entry_password_set(entry, EINA_TRUE);
+ evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, 0);
+ evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, 0.5);
+ evas_object_smart_callback_add(entry, "activated",
+ _entry_activated_cb, ad);
+ elm_box_pack_end(box, entry);
+ evas_object_show(entry);
+ ad->entry = entry;
+
+ check = elm_check_add(box);
+ elm_object_text_set(check, _("Show password"));
+ elm_check_state_set(check, EINA_FALSE);
+ evas_object_size_hint_align_set(check, 0.0, 0.5);
+ evas_object_smart_callback_add(check, "changed",
+ _show_password_cb, entry);
+ elm_box_pack_end(box, check);
+ evas_object_show(check);
+
+ evas_object_show(frame);
+ e_dialog_content_set(dialog, frame, 280, 100);
e_dialog_show(dialog);
evas_object_event_callback_add(dialog->bg_object, EVAS_CALLBACK_KEY_DOWN,
_dialog_key_down_cb, ad);
e_object_del_attach_func_set(E_OBJECT(dialog), _dialog_del_cb);
e_object_data_set(E_OBJECT(dialog), ad);
- e_dialog_button_focus_num(dialog, 0);
+ elm_object_focus_set(entry, EINA_TRUE);
elm_win_center(dialog->win, 1, 1);
- _dialog_psk_add(dialog, ssid);
-
return ad;
}
@@ -259,9 +211,8 @@ static void
_agent_ui_request_cb(void *data EINA_UNUSED, E_NM_Agent_Request *req,
const char *ssid)
{
- /* Only one dialog at a time — drop any stale one. The data layer
- * already freed the previous request when it arrived, so just tear
- * down the widgets here. */
+ /* Only one dialog at a time — drop any stale one. The data layer has
+ * already freed the previous request, so we just tear down widgets. */
if (_current_dialog)
{
_current_dialog->req = NULL; /* don't reply — request is gone */
@@ -283,7 +234,7 @@ _agent_ui_cancel_cb(void *data EINA_UNUSED,
E_NM_Agent_Request *req EINA_UNUSED)
{
/* NM is withdrawing the pending request. Dismiss the dialog without
- * sending any reply — the data layer will free the request after this
+ * sending any reply — the data layer frees the request after this
* callback returns. */
if (_current_dialog)
{
diff --git a/src/modules/networkmanager/e_mod_main.c b/src/modules/networkmanager/e_mod_main.c
index 00b1cb007..768c4ed4c 100644
--- a/src/modules/networkmanager/e_mod_main.c
+++ b/src/modules/networkmanager/e_mod_main.c
@@ -741,10 +741,10 @@ _enm_popup_update(struct NM_Manager *nm, E_NM_Instance *inst)
{
char ipbuf[128];
snprintf(ipbuf, sizeof(ipbuf), "IP: %s", nm->ip_address);
- e_widget_label_text_set(inst->ui.popup.ip_label, ipbuf);
+ elm_object_text_set(inst->ui.popup.ip_label, ipbuf);
}
else
- e_widget_label_text_set(inst->ui.popup.ip_label, "");
+ elm_object_text_set(inst->ui.popup.ip_label, "");
}
@@ -781,7 +781,6 @@ _enm_popup_new(E_NM_Instance *inst)
{
E_NM_Module_Context *ctxt = inst->ctxt;
Evas_Object *box, *gl;
- Evas *evas;
Elm_Genlist_Item_Class *itc;
EINA_SAFETY_ON_FALSE_RETURN(inst->popup == NULL);
@@ -791,7 +790,6 @@ _enm_popup_new(E_NM_Instance *inst)
e_nm_scan(ctxt->nm);
inst->popup = e_gadcon_popup_new(inst->gcc, 0);
- evas = e_comp->evas;
/* Outer elm box to stack genlist + IP label */
box = elm_box_add(e_comp->elm);
@@ -846,7 +844,12 @@ _enm_popup_new(E_NM_Instance *inst)
elm_box_pack_end(box, gl);
/* IP address label */
- inst->ui.popup.ip_label = e_widget_label_add(evas, "");
+ inst->ui.popup.ip_label = elm_label_add(box);
+ evas_object_size_hint_align_set(inst->ui.popup.ip_label,
+ EVAS_HINT_FILL, 0.5);
+ evas_object_size_hint_weight_set(inst->ui.popup.ip_label,
+ EVAS_HINT_EXPAND, 0);
+ elm_object_text_set(inst->ui.popup.ip_label, "");
elm_box_pack_end(box, inst->ui.popup.ip_label);
evas_object_show(inst->ui.popup.ip_label);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.