manager: track Adapter objects + clear list on disable

Promote Adapter to a first-class manager object (Iwd_Adapter with
PropertiesChanged subscription). iwd_manager_set_powered now drives
the adapter directly, so Enable still works after Disable has torn
down the device hash. State recomputation also looks at any
powered adapter, and the popup hides the network list while
state == IWD_STATE_OFF.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
nemunaire 2026-04-09 10:58:47 +07:00
commit 1b5dd32c0b
7 changed files with 239 additions and 12 deletions

View file

@ -2,6 +2,7 @@
#include "iwd_dbus.h"
#include "iwd_props.h"
#include "iwd_manager.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -127,6 +128,8 @@ iwd_device_free(Iwd_Device *d)
iwd_device_detach_station(d);
if (d->sh_dev_props) eldbus_signal_handler_del(d->sh_dev_props);
if (d->device_proxy) eldbus_proxy_unref(d->device_proxy);
if (d->adapter_proxy) eldbus_proxy_unref(d->adapter_proxy);
if (d->adapter_obj) eldbus_object_unref(d->adapter_obj);
if (d->obj) eldbus_object_unref(d->obj);
free(d->path);
free(d->name);
@ -136,23 +139,70 @@ iwd_device_free(Iwd_Device *d)
free(d);
}
static void
_log_reply(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED)
{
const char *what = data;
const char *en, *em;
if (eldbus_message_error_get(msg, &en, &em))
fprintf(stderr, "e_iwd: %s failed: %s: %s\n", what, en, em);
else
fprintf(stderr, "e_iwd: %s ok\n", what);
}
void
iwd_device_set_powered(Iwd_Device *d, Eina_Bool on)
{
if (!d || !d->device_proxy) return;
eldbus_proxy_property_set(d->device_proxy, "Powered", "b", &on, NULL, NULL);
if (!d) return;
Eina_Bool v = on;
/* Toggle the radio at the Adapter level — that's what actually takes
* the interface up/down on modern iwd. Device.Powered is a no-op on
* many installs. Keep the adapter proxy alive on the device so the
* pending property_set isn't canceled. */
if (d->adapter_path && d->obj && !d->adapter_proxy)
{
Eldbus_Connection *conn = eldbus_object_connection_get(d->obj);
d->adapter_obj = eldbus_object_get(conn, IWD_BUS_NAME, d->adapter_path);
if (d->adapter_obj)
d->adapter_proxy = eldbus_proxy_get(d->adapter_obj, IWD_IFACE_ADAPTER);
}
if (d->adapter_proxy)
eldbus_proxy_property_set(d->adapter_proxy, "Powered", "b", &v, _log_reply,
on ? "Adapter.Powered=true"
: "Adapter.Powered=false");
else
fprintf(stderr, "e_iwd: set_powered: no Adapter for %s\n",
d->path ? d->path : "?");
if (d->device_proxy)
eldbus_proxy_property_set(d->device_proxy, "Powered", "b", &v, NULL, NULL);
}
void
iwd_device_scan(Iwd_Device *d)
{
if (!d || !d->station_proxy) return;
eldbus_proxy_call(d->station_proxy, "Scan", NULL, NULL, -1, "");
if (!d)
{
fprintf(stderr, "e_iwd: scan: NULL device\n");
return;
}
if (!d->station_proxy)
{
fprintf(stderr, "e_iwd: scan: no Station proxy on %s\n",
d->path ? d->path : "?");
return;
}
eldbus_proxy_call(d->station_proxy, "Scan", _log_reply, "Scan", -1, "");
}
void
iwd_device_disconnect(Iwd_Device *d)
{
if (!d || !d->station_proxy) return;
eldbus_proxy_call(d->station_proxy, "Disconnect", NULL, NULL, -1, "");
if (!d || !d->station_proxy)
{
fprintf(stderr, "e_iwd: disconnect: missing Station proxy\n");
return;
}
eldbus_proxy_call(d->station_proxy, "Disconnect", _log_reply, "Disconnect", -1, "");
}