Compare commits

...

4 commits

Author SHA1 Message Date
7a6e205002 WIP 2025-12-28 22:38:39 +07:00
ce323cdaf8 Fix module shutdown order to prevent signal handler double-free
The shutdown sequence was freeing D-Bus resources before cleaning up
devices and networks, causing devices/networks to attempt deleting
already-freed signal handlers.

Shutdown order fixed:
1. Gadget shutdown
2. Network shutdown (frees networks and their signal handlers)
3. Device shutdown (frees devices and their signal handlers)
4. State shutdown
5. Agent shutdown
6. D-Bus shutdown (closes connection and frees proxies)

This ensures signal handlers are properly deleted while the D-Bus
connection is still active, preventing the 'Eina Magic Check Failed'
error during module unload.

Fixes: CRI: eldbus_signal_handler_del() Magic Check Failed
2025-12-28 21:53:22 +07:00
d76a77b5b3 Fix critical D-Bus and gadget integration issues
This commit fixes several critical bugs preventing the module from working:

1. Agent D-Bus Object Lifecycle Fix:
   - Keep manager_obj reference alive in IWD_Agent structure
   - Prevents async RegisterAgent call from being canceled
   - Fixes 'Canceled by user' error during agent registration
   - Object is now properly unreferenced during shutdown

2. Signal Handler Cleanup Fix:
   - Don't manually delete signal handlers after object unref
   - eldbus_object_unref() automatically cleans up handlers
   - Prevents 'Eina Magic Check Failed' error on module unload
   - Fixes double-free of signal handlers

3. Gadget Integration Fix:
   - Set gcc->o_base directly to attach icon to gadcon
   - Prevents shelf layout corruption when adding module
   - Proper Enlightenment gadcon integration

4. Agent Path Fix:
   - Use IWD_DAEMON_PATH ('/net/connman/iwd') for AgentManager
   - AgentManager interface is on daemon object, not root
   - Fixes 'No matching method found' error

These fixes resolve:
- Module load/unload crashes
- Shelf disorganization
- Agent registration failures
- D-Bus signal handler corruption

The module should now load cleanly, register the agent successfully,
and unload without errors.
2025-12-28 21:51:41 +07:00
3a2a583409 Fix module architecture string to match Enlightenment expectations
The module architecture was incorrectly constructed as:
  linux-x86_64-0.27

But Enlightenment expects:
  linux-gnu-x86_64-0.27.1

Changes:
- Detect system ABI (gnu/musl) via features.h header check
- Use full Enlightenment version instead of just major.minor
- Correct architecture format: <system>-<abi>-<cpu>-<version>

This ensures the module installs to the correct directory that
Enlightenment will find when loading modules.

Also updated Gentoo ebuild to set S variable for correct source
directory extraction (git archives extract to 'eiwd' not 'eiwd-0.1.0').
2025-12-28 20:39:27 +07:00
11 changed files with 131 additions and 64 deletions

View file

@ -13,18 +13,28 @@ evas = dependency('evas')
edje = dependency('edje') edje = dependency('edje')
eina = dependency('eina') eina = dependency('eina')
# Get Enlightenment module API version # Get Enlightenment version and module architecture
e_version = enlightenment.version().split('.') e_version = enlightenment.version()
e_major = e_version[0]
e_minor = e_version[1] # Detect system ABI (gnu, musl, etc.)
cc = meson.get_compiler('c')
if cc.has_header('features.h')
# GNU libc systems
system_abi = 'gnu'
else
# Try to detect from system - fallback to 'unknown'
system_abi = 'unknown'
endif
# Installation paths # Installation paths
module_name = 'iwd' module_name = 'iwd'
module_arch = '@0@-@1@-@2@.@3@'.format( # Format: <system>-<abi>-<cpu>-<version>
# Example: linux-gnu-x86_64-0.27.1
module_arch = '@0@-@1@-@2@-@3@'.format(
host_machine.system(), host_machine.system(),
system_abi,
host_machine.cpu_family(), host_machine.cpu_family(),
e_major, e_version
e_minor
) )
dir_module = join_paths(get_option('libdir'), 'enlightenment', 'modules', module_name) dir_module = join_paths(get_option('libdir'), 'enlightenment', 'modules', module_name)

2
metadata/layout.conf Normal file
View file

@ -0,0 +1,2 @@
masters = gentoo
repo-name = x-eiwd

View file

@ -6,14 +6,16 @@ EAPI=8
inherit meson inherit meson
DESCRIPTION="Enlightenment Wi-Fi module using iwd backend" DESCRIPTION="Enlightenment Wi-Fi module using iwd backend"
HOMEPAGE="https://github.com/yourusername/eiwd" HOMEPAGE="https://git.nemunai.re/nemunaire/eiwd"
SRC_URI="https://github.com/yourusername/eiwd/archive/v${PV}.tar.gz -> ${P}.tar.gz" SRC_URI="https://git.nemunai.re/nemunaire/eiwd/archive/v${PV}.tar.gz -> ${P}.tar.gz"
LICENSE="BSD" # Adjust based on chosen license LICENSE="BSD"
SLOT="0" SLOT="0"
KEYWORDS="~amd64 ~x86 ~arm64" KEYWORDS="~amd64 ~x86 ~arm64"
IUSE="nls" IUSE="nls"
S="${WORKDIR}/${PN}"
RDEPEND=" RDEPEND="
>=x11-wm/enlightenment-0.25.0 >=x11-wm/enlightenment-0.25.0
>=dev-libs/efl-1.26.0 >=dev-libs/efl-1.26.0

View file

@ -0,0 +1 @@
x-eiwd

View file

@ -63,21 +63,8 @@ _gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style)
inst = E_NEW(Instance, 1); inst = E_NEW(Instance, 1);
if (!inst) return NULL; if (!inst) return NULL;
/* Create gadcon client */ /* Create edje object */
gcc = e_gadcon_client_new(gc, name, id, style, NULL); o = edje_object_add(gc->evas);
if (!gcc)
{
E_FREE(inst);
return NULL;
}
gcc->data = inst;
inst->gcc = gcc;
/* Create icon */
o = edje_object_add(gcc->gadcon->evas);
inst->icon = o;
inst->gadget = o;
/* Load theme */ /* Load theme */
char theme_path[PATH_MAX]; char theme_path[PATH_MAX];
@ -91,18 +78,26 @@ _gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style)
evas_object_color_set(o, 100, 150, 200, 255); evas_object_color_set(o, 100, 150, 200, 255);
} }
evas_object_resize(o, 16, 16);
evas_object_show(o); evas_object_show(o);
/* Pass the object directly to e_gadcon_client_new */
gcc = e_gadcon_client_new(gc, name, id, style, o);
if (!gcc)
{
evas_object_del(o);
E_FREE(inst);
return NULL;
}
gcc->data = inst;
inst->gcc = gcc;
inst->icon = o;
inst->gadget = o;
/* Add mouse event handler */ /* Add mouse event handler */
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN,
_gadget_mouse_down_cb, inst); _gadget_mouse_down_cb, inst);
/* Set gadcon object */
e_gadcon_client_min_size_set(gcc, 16, 16);
e_gadcon_client_aspect_set(gcc, 16, 16);
e_gadcon_client_show(gcc);
/* Get first available device */ /* Get first available device */
Eina_List *devices = iwd_devices_get(); Eina_List *devices = iwd_devices_get();
if (devices && eina_list_count(devices) > 0) if (devices && eina_list_count(devices) > 0)
@ -164,8 +159,21 @@ _gc_shutdown(E_Gadcon_Client *gcc)
static void static void
_gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient EINA_UNUSED) _gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient EINA_UNUSED)
{ {
e_gadcon_client_aspect_set(gcc, 16, 16); Instance *inst;
e_gadcon_client_min_size_set(gcc, 16, 16); Evas_Coord mw, mh;
inst = gcc->data;
if (!inst || !inst->icon) return;
mw = 0;
mh = 0;
edje_object_size_min_get(inst->icon, &mw, &mh);
if ((mw < 1) || (mh < 1))
edje_object_size_min_calc(inst->icon, &mw, &mh);
if (mw < 4) mw = 4;
if (mh < 4) mh = 4;
e_gadcon_client_aspect_set(gcc, mw, mh);
e_gadcon_client_min_size_set(gcc, mw, mh);
} }
/* Gadcon label */ /* Gadcon label */
@ -194,25 +202,30 @@ _gc_icon(const E_Gadcon_Client_Class *client_class EINA_UNUSED, Evas *evas)
{ {
/* Fallback to simple colored box */ /* Fallback to simple colored box */
evas_object_color_set(o, 100, 150, 200, 255); evas_object_color_set(o, 100, 150, 200, 255);
evas_object_resize(o, 16, 16);
} }
} }
else else
{ {
/* Fallback if module not initialized yet */ /* Fallback if module not initialized yet */
evas_object_color_set(o, 100, 150, 200, 255); evas_object_color_set(o, 100, 150, 200, 255);
evas_object_resize(o, 16, 16);
} }
evas_object_resize(o, 16, 16); evas_object_show(o);
return o; return o;
} }
/* Generate new ID */ /* Generate new ID */
static const char * static const char *
_gc_id_new(const E_Gadcon_Client_Class *client_class EINA_UNUSED) _gc_id_new(const E_Gadcon_Client_Class *client_class)
{ {
static char buf[32]; static char buf[128];
snprintf(buf, sizeof(buf), "%s.%d", _gc_class.name, rand()); Mod *mod = iwd_mod;
snprintf(buf, sizeof(buf), "%s.%d", client_class->name,
mod ? eina_list_count(mod->instances) + 1 : 1);
return buf; return buf;
} }
@ -225,19 +238,36 @@ _gadget_mouse_down_cb(void *data, Evas *e EINA_UNUSED,
Instance *inst = data; Instance *inst = data;
Evas_Event_Mouse_Down *ev = event_info; Evas_Event_Mouse_Down *ev = event_info;
if (!inst) return; if (!inst)
{
e_util_dialog_show("Debug", "Instance is NULL!");
return;
}
if (ev->button == 1) /* Left click */ if (ev->button == 1) /* Left click */
{ {
INF("Gadget clicked - popup=%p device=%p", inst->popup, inst->device);
if (inst->popup) if (inst->popup)
{ {
/* Close popup */ /* Close popup */
INF("Closing popup");
iwd_popup_del(inst); iwd_popup_del(inst);
} }
else else
{ {
/* Open popup */ /* Open popup */
INF("Opening popup");
iwd_popup_new(inst); iwd_popup_new(inst);
/* Debug: Check if popup was created */
if (!inst->popup)
{
ERR("Failed to create popup!");
e_util_dialog_show("IWD Debug",
"Popup creation failed.<br>"
"Check if iwd is running and wireless device exists.");
}
} }
} }
} }

View file

@ -87,13 +87,15 @@ e_modapi_shutdown(E_Module *m EINA_UNUSED)
/* Shutdown gadget */ /* Shutdown gadget */
e_iwd_gadget_shutdown(); e_iwd_gadget_shutdown();
/* Shutdown D-Bus and iwd subsystems */ /* Shutdown iwd subsystems (must happen before D-Bus shutdown) */
iwd_agent_shutdown();
iwd_dbus_shutdown();
iwd_network_shutdown(); iwd_network_shutdown();
iwd_device_shutdown(); iwd_device_shutdown();
iwd_state_shutdown(); iwd_state_shutdown();
/* Shutdown D-Bus (this frees all proxies and handlers) */
iwd_agent_shutdown();
iwd_dbus_shutdown();
/* Free configuration */ /* Free configuration */
_iwd_config_free(); _iwd_config_free();
e_iwd_config_shutdown(); e_iwd_config_shutdown();

View file

@ -18,16 +18,31 @@ iwd_popup_new(Instance *inst)
IWD_Network *net; IWD_Network *net;
Eina_List *l; Eina_List *l;
if (!inst) return; if (!inst)
if (inst->popup) return; {
ERR("iwd_popup_new: inst is NULL");
return;
}
DBG("Creating popup"); if (inst->popup)
{
DBG("Popup already exists");
return;
}
INF("Creating popup for instance %p", inst);
/* Create popup */ /* Create popup */
popup = e_gadcon_popup_new(inst->gcc, 0); popup = e_gadcon_popup_new(inst->gcc, 0);
if (!popup) return; if (!popup)
{
ERR("e_gadcon_popup_new failed!");
e_util_dialog_show("IWD Error", "Failed to create gadcon popup");
return;
}
inst->popup = (void *)popup; inst->popup = (void *)popup;
INF("Popup created: %p", popup);
/* Create main box */ /* Create main box */
box = elm_box_add(e_comp->elm); box = elm_box_add(e_comp->elm);

View file

@ -66,6 +66,12 @@ iwd_agent_init(void)
return EINA_FALSE; return EINA_FALSE;
} }
/* Initialize fields */
iwd_agent->manager_obj = NULL;
iwd_agent->pending_network_path = NULL;
iwd_agent->pending_passphrase = NULL;
iwd_agent->pending_msg = NULL;
/* Register D-Bus service interface */ /* Register D-Bus service interface */
iwd_agent->iface = eldbus_service_interface_register(conn, IWD_AGENT_PATH, &agent_desc); iwd_agent->iface = eldbus_service_interface_register(conn, IWD_AGENT_PATH, &agent_desc);
if (!iwd_agent->iface) if (!iwd_agent->iface)
@ -76,11 +82,11 @@ iwd_agent_init(void)
return EINA_FALSE; return EINA_FALSE;
} }
/* Register agent with iwd */ /* Register agent with iwd daemon (AgentManager is at /net/connman/iwd) */
obj = eldbus_object_get(conn, IWD_SERVICE, IWD_MANAGER_PATH); obj = eldbus_object_get(conn, IWD_SERVICE, IWD_DAEMON_PATH);
if (!obj) if (!obj)
{ {
ERR("Failed to get iwd manager object"); ERR("Failed to get iwd daemon object");
eldbus_service_interface_unregister(iwd_agent->iface); eldbus_service_interface_unregister(iwd_agent->iface);
E_FREE(iwd_agent); E_FREE(iwd_agent);
iwd_agent = NULL; iwd_agent = NULL;
@ -98,11 +104,12 @@ iwd_agent_init(void)
return EINA_FALSE; return EINA_FALSE;
} }
/* Store object reference to keep it alive during async call */
iwd_agent->manager_obj = obj;
eldbus_proxy_call(proxy, "RegisterAgent", _agent_register_cb, NULL, -1, "o", IWD_AGENT_PATH); eldbus_proxy_call(proxy, "RegisterAgent", _agent_register_cb, NULL, -1, "o", IWD_AGENT_PATH);
eldbus_object_unref(obj); INF("Agent initialization started");
INF("Agent initialized");
return EINA_TRUE; return EINA_TRUE;
} }
@ -119,6 +126,9 @@ iwd_agent_shutdown(void)
if (iwd_agent->iface) if (iwd_agent->iface)
eldbus_service_interface_unregister(iwd_agent->iface); eldbus_service_interface_unregister(iwd_agent->iface);
if (iwd_agent->manager_obj)
eldbus_object_unref(iwd_agent->manager_obj);
eina_stringshare_del(iwd_agent->pending_network_path); eina_stringshare_del(iwd_agent->pending_network_path);
eina_stringshare_del(iwd_agent->pending_passphrase); eina_stringshare_del(iwd_agent->pending_passphrase);
@ -216,7 +226,7 @@ _agent_unregister(void)
conn = iwd_dbus_conn_get(); conn = iwd_dbus_conn_get();
if (!conn) return; if (!conn) return;
obj = eldbus_object_get(conn, IWD_SERVICE, IWD_MANAGER_PATH); obj = eldbus_object_get(conn, IWD_SERVICE, IWD_DAEMON_PATH);
if (!obj) return; if (!obj) return;
proxy = eldbus_proxy_get(obj, IWD_AGENT_MANAGER_INTERFACE); proxy = eldbus_proxy_get(obj, IWD_AGENT_MANAGER_INTERFACE);

View file

@ -10,6 +10,7 @@
typedef struct _IWD_Agent typedef struct _IWD_Agent
{ {
Eldbus_Service_Interface *iface; Eldbus_Service_Interface *iface;
Eldbus_Object *manager_obj; /* Keep reference to prevent call cancellation */
const char *pending_network_path; const char *pending_network_path;
const char *pending_passphrase; const char *pending_passphrase;
const Eldbus_Message *pending_msg; /* Stored message to reply to */ const Eldbus_Message *pending_msg; /* Stored message to reply to */

View file

@ -157,24 +157,17 @@ _iwd_dbus_disconnect(void)
DBG("Disconnecting from iwd daemon"); DBG("Disconnecting from iwd daemon");
if (iwd_dbus->interfaces_added) /* Unref the object first - this will clean up associated signal handlers */
{
eldbus_signal_handler_del(iwd_dbus->interfaces_added);
iwd_dbus->interfaces_added = NULL;
}
if (iwd_dbus->interfaces_removed)
{
eldbus_signal_handler_del(iwd_dbus->interfaces_removed);
iwd_dbus->interfaces_removed = NULL;
}
if (iwd_dbus->manager_obj) if (iwd_dbus->manager_obj)
{ {
eldbus_object_unref(iwd_dbus->manager_obj); eldbus_object_unref(iwd_dbus->manager_obj);
iwd_dbus->manager_obj = NULL; iwd_dbus->manager_obj = NULL;
} }
/* Clear handler pointers (they're already freed by object unref) */
iwd_dbus->interfaces_added = NULL;
iwd_dbus->interfaces_removed = NULL;
iwd_dbus->connected = EINA_FALSE; iwd_dbus->connected = EINA_FALSE;
} }

View file

@ -7,6 +7,7 @@
/* iwd D-Bus service and interfaces */ /* iwd D-Bus service and interfaces */
#define IWD_SERVICE "net.connman.iwd" #define IWD_SERVICE "net.connman.iwd"
#define IWD_MANAGER_PATH "/" #define IWD_MANAGER_PATH "/"
#define IWD_DAEMON_PATH "/net/connman/iwd"
#define IWD_MANAGER_INTERFACE "net.connman.iwd.Manager" #define IWD_MANAGER_INTERFACE "net.connman.iwd.Manager"
#define IWD_ADAPTER_INTERFACE "net.connman.iwd.Adapter" #define IWD_ADAPTER_INTERFACE "net.connman.iwd.Adapter"
#define IWD_DEVICE_INTERFACE "net.connman.iwd.Device" #define IWD_DEVICE_INTERFACE "net.connman.iwd.Device"