Added comprehensive theming and configuration support:
Core Changes:
- Created data/theme.edc with Edje theme groups for gadget states
(disconnected, connecting, connected, error) with color-coded icons
- Implemented signal-based theme updates (e,state,* signals)
- Created e_mod_config.c with full configuration dialog
- Added i18n support structure (po/ directory)
Configuration Dialog:
- Auto-connect to known networks toggle
- Show hidden networks toggle
- Signal refresh interval slider (1-60s)
- Adapter selection UI (for multi-adapter systems)
- Saves via e_config_save_queue()
Theme Integration:
- Gadget loads e-module-iwd.edj theme file
- Falls back to simple colored rectangles if theme missing
- State changes emit Edje signals to theme
- Signal strength indicator support
Build System:
- Updated data/meson.build to compile theme with edje_cc
- Added i18n framework with po/meson.build
- Created meson_options.txt with nls option
- Added po/POTFILES.in for translatable strings
Module Statistics:
- Module size: 232KB (includes config dialog + theme loading)
- Theme file: 11KB (e-module-iwd.edj)
- Total lines of code: ~3,500+
- New files: 5 (theme.edc, e_mod_config.c, 3 i18n files)
API Compatibility:
- Fixed E_Container deprecation (E 0.27+ uses NULL)
- Updated e_iwd_config_show() signature
- Proper edje_object_file_get() usage with output parameters
The gadget now has professional theme support with visual state
feedback. Configuration can be accessed through standard E module
settings. i18n framework ready for translations.
🎨 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
421 lines
12 KiB
Markdown
421 lines
12 KiB
Markdown
# Implementation Plan: eiwd - Enlightenment Wi-Fi Module (iwd Backend)
|
|
|
|
## Project Overview
|
|
|
|
Create a production-ready Enlightenment module that manages Wi-Fi connections using iwd's D-Bus API, providing a gadget + popup UI following Enlightenment conventions.
|
|
|
|
**Current State**: Fresh workspace with only CLAUDE.md PRD
|
|
**Target**: Feature parity with econnman Wi-Fi functionality using iwd instead of ConnMan
|
|
|
|
## System Context
|
|
|
|
- **Enlightenment**: 0.27.1 (Module API version 25)
|
|
- **iwd daemon**: Running and accessible via D-Bus (`net.connman.iwd`)
|
|
- **Build tools**: Meson, GCC, pkg-config available
|
|
- **Libraries**: EFL (eldbus, elementary, ecore, evas, edje, eina) + E headers
|
|
|
|
## Implementation Phases
|
|
|
|
### Phase 1: Build System & Module Skeleton
|
|
|
|
**Goal**: Create loadable .so module with proper build infrastructure
|
|
|
|
**Files to Create**:
|
|
- `meson.build` (root) - Project definition, dependencies, installation paths
|
|
- `src/meson.build` - Source compilation
|
|
- `data/meson.build` - Desktop file and theme compilation
|
|
- `data/module.desktop` - Module metadata
|
|
- `src/e_mod_main.c` - Module entry point (e_modapi_init/shutdown/save)
|
|
- `src/e_mod_main.h` - Module structures and config
|
|
|
|
**Key Components**:
|
|
|
|
1. **Meson root build**:
|
|
- Dependencies: enlightenment, eldbus, elementary, ecore, evas, edje, eina
|
|
- Installation path: `/usr/lib64/enlightenment/modules/iwd/linux-gnu-x86_64-0.27/module.so`
|
|
|
|
2. **Module entry point** (`e_mod_main.c`):
|
|
```c
|
|
E_API E_Module_Api e_modapi = { E_MODULE_API_VERSION, "IWD" };
|
|
E_API void *e_modapi_init(E_Module *m);
|
|
E_API int e_modapi_shutdown(E_Module *m);
|
|
E_API int e_modapi_save(E_Module *m);
|
|
```
|
|
|
|
3. **Config structure** (stored via EET):
|
|
- config_version
|
|
- auto_connect (bool)
|
|
- show_hidden_networks (bool)
|
|
- signal_refresh_interval
|
|
- preferred_adapter
|
|
|
|
**Verification**: Module loads in Enlightenment without crashing
|
|
|
|
---
|
|
|
|
### Phase 2: D-Bus Layer (iwd Backend)
|
|
|
|
**Goal**: Establish communication with iwd daemon and abstract devices/networks
|
|
|
|
**Files to Create**:
|
|
- `src/iwd/iwd_dbus.c` + `.h` - D-Bus connection management
|
|
- `src/iwd/iwd_device.c` + `.h` - Device abstraction (Station interface)
|
|
- `src/iwd/iwd_network.c` + `.h` - Network abstraction
|
|
- `src/iwd/iwd_agent.c` + `.h` - Agent for passphrase requests
|
|
|
|
**Key Implementations**:
|
|
|
|
1. **D-Bus Manager** (`iwd_dbus.c`):
|
|
- Connect to system bus `net.connman.iwd`
|
|
- Subscribe to ObjectManager signals (InterfacesAdded/Removed)
|
|
- Monitor NameOwnerChanged for iwd daemon restart
|
|
- Provide signal subscription helpers
|
|
|
|
2. **Device Abstraction** (`iwd_device.c`):
|
|
```c
|
|
typedef struct _IWD_Device {
|
|
char *path, *name, *address;
|
|
Eina_Bool powered, scanning;
|
|
char *state; // "disconnected", "connecting", "connected"
|
|
Eldbus_Proxy *device_proxy, *station_proxy;
|
|
} IWD_Device;
|
|
```
|
|
- Operations: scan, disconnect, connect_hidden, get_networks
|
|
|
|
3. **Network Abstraction** (`iwd_network.c`):
|
|
```c
|
|
typedef struct _IWD_Network {
|
|
char *path, *name, *type; // "open", "psk", "8021x"
|
|
Eina_Bool known;
|
|
int16_t signal_strength; // dBm
|
|
Eldbus_Proxy *network_proxy;
|
|
} IWD_Network;
|
|
```
|
|
- Operations: connect, forget
|
|
|
|
4. **Agent Implementation** (`iwd_agent.c`):
|
|
- Register D-Bus service at `/org/enlightenment/eiwd/agent`
|
|
- Implement `RequestPassphrase(network_path)` method
|
|
- Bridge between iwd requests and UI dialogs
|
|
- **Security**: Never log passphrases, clear from memory after sending
|
|
|
|
**Verification**: Can list devices, trigger scan, receive PropertyChanged signals
|
|
|
|
---
|
|
|
|
### Phase 3: Gadget & Basic UI
|
|
|
|
**Goal**: Create shelf icon and popup interface
|
|
|
|
**Files to Create**:
|
|
- `src/e_mod_gadget.c` - Gadcon provider and icon
|
|
- `src/e_mod_popup.c` - Popup window and layout
|
|
- `src/ui/wifi_status.c` + `.h` - Current connection widget
|
|
- `src/ui/wifi_list.c` + `.h` - Network list widget
|
|
|
|
**Key Implementations**:
|
|
|
|
1. **Gadcon Provider** (`e_mod_gadget.c`):
|
|
```c
|
|
static const E_Gadcon_Client_Class _gc_class = {
|
|
GADCON_CLIENT_CLASS_VERSION, "iwd", { ... }
|
|
};
|
|
```
|
|
- Icon states via edje: disconnected, connecting, connected (signal tiers), error
|
|
- Click handler: toggle popup
|
|
- Tooltip: SSID, signal strength, security type
|
|
|
|
2. **Popup Window** (`e_mod_popup.c`):
|
|
- Layout: Current Connection + Available Networks + Actions
|
|
- Current: SSID, signal, IP, disconnect button
|
|
- Networks: sorted by known → signal strength
|
|
- Actions: Rescan, Enable/Disable Wi-Fi
|
|
|
|
3. **Network List Widget** (`ui/wifi_list.c`):
|
|
- Use elm_genlist or e_widget_ilist
|
|
- Icons: open/WPA2/WPA3 lock icons
|
|
- Sort: known networks first, then by signal
|
|
- Click handler: initiate connection
|
|
|
|
**Verification**: Gadget appears on shelf, popup opens/closes, networks display
|
|
|
|
---
|
|
|
|
### Phase 4: Connection Management
|
|
|
|
**Goal**: Complete connection flow including authentication
|
|
|
|
**Files to Create**:
|
|
- `src/ui/wifi_auth.c` + `.h` - Passphrase dialog
|
|
- `src/iwd/iwd_state.c` + `.h` - State machine
|
|
|
|
**Connection Flow**:
|
|
1. User clicks network in list
|
|
2. Check security type (open vs psk vs 8021x)
|
|
3. If psk: show auth dialog (`wifi_auth_dialog_show`)
|
|
4. Call `network.Connect()` D-Bus method
|
|
5. iwd calls agent's `RequestPassphrase`
|
|
6. Return passphrase from dialog
|
|
7. Monitor `Station.State` PropertyChanged
|
|
8. Update UI: connecting → connected
|
|
|
|
**State Machine** (`iwd_state.c`):
|
|
```c
|
|
typedef enum {
|
|
IWD_STATE_OFF, // Powered = false
|
|
IWD_STATE_IDLE, // Powered = true, disconnected
|
|
IWD_STATE_SCANNING,
|
|
IWD_STATE_CONNECTING,
|
|
IWD_STATE_CONNECTED,
|
|
IWD_STATE_ERROR // iwd not running
|
|
} IWD_State;
|
|
```
|
|
|
|
**Known Networks**:
|
|
- List via KnownNetwork interface
|
|
- Operations: Forget, Set AutoConnect
|
|
- UI: star icon for known, context menu
|
|
|
|
**Verification**: Connect to open/WPA2 networks, disconnect, forget network
|
|
|
|
---
|
|
|
|
### Phase 5: Advanced Features
|
|
|
|
**Goal**: Handle edge cases and advanced scenarios
|
|
|
|
**Implementations**:
|
|
|
|
1. **Hidden Networks**:
|
|
- Add "Connect to Hidden Network" button
|
|
- Call `Station.ConnectHiddenNetwork(ssid)`
|
|
|
|
2. **Multiple Adapters**:
|
|
- Monitor all `/net/connman/iwd/[0-9]+` paths
|
|
- UI: dropdown/tabs if multiple devices
|
|
- Config: preferred adapter selection
|
|
|
|
3. **Daemon Restart Handling**:
|
|
- Monitor NameOwnerChanged for `net.connman.iwd`
|
|
- On restart: re-query ObjectManager, re-register agent, recreate proxies
|
|
- Set error state while daemon down
|
|
|
|
4. **Polkit Integration**:
|
|
- Detect `NotAuthorized` errors
|
|
- Show user-friendly permission error dialog
|
|
- Document required polkit rules (don't auto-install)
|
|
|
|
**Error Handling**:
|
|
- iwd not running → error state icon
|
|
- No wireless device → graceful message
|
|
- Permission denied → polkit error dialog
|
|
- Auth failure → clear error message (wrong password)
|
|
|
|
**Verification**: Handle iwd restart, multiple adapters, polkit errors
|
|
|
|
---
|
|
|
|
### Phase 6: Theme & Polish
|
|
|
|
**Goal**: Professional UI appearance and internationalization
|
|
|
|
**Files to Create**:
|
|
- `data/theme.edc` - Edje theme definition
|
|
- `data/icons/*.svg` - Icon source files
|
|
- `po/POTFILES.in` - i18n file list
|
|
- `po/eiwd.pot` - Translation template
|
|
- `src/e_mod_config.c` - Configuration dialog
|
|
|
|
**Theme Groups** (`theme.edc`):
|
|
- `e/modules/iwd/main` - Gadget icon
|
|
- `e/modules/iwd/signal/{0,25,50,75,100}` - Signal strength icons
|
|
|
|
**Configuration Dialog** (`e_mod_config.c`):
|
|
- Auto-connect to known networks: checkbox
|
|
- Show hidden networks: checkbox
|
|
- Signal refresh interval: slider (1-60s)
|
|
- Preferred adapter: dropdown
|
|
|
|
**i18n**:
|
|
- Mark strings with `D_(str)` macro (dgettext)
|
|
- Meson gettext integration
|
|
|
|
**Verification**: Theme scales properly, config saves, translations work
|
|
|
|
---
|
|
|
|
### Phase 7: Testing & Documentation
|
|
|
|
**Testing**:
|
|
- Unit tests: SSID parsing, signal conversion, config serialization
|
|
- Memory leak check: Valgrind during connect/disconnect cycles
|
|
- Manual checklist:
|
|
- [ ] Module loads without errors
|
|
- [ ] Scan, connect, disconnect work
|
|
- [ ] Wrong password shows error
|
|
- [ ] Known network auto-connect
|
|
- [ ] iwd restart recovery
|
|
- [ ] Suspend/resume handling
|
|
- [ ] No device graceful degradation
|
|
|
|
**Documentation** (`README.md`, `INSTALL.md`):
|
|
- Overview and features
|
|
- Dependencies
|
|
- Building with Meson
|
|
- Installation paths
|
|
- iwd setup requirements
|
|
- Polkit configuration
|
|
- Troubleshooting
|
|
|
|
**Verification**: All tests pass, documentation complete
|
|
|
|
---
|
|
|
|
### Phase 8: Packaging & Distribution
|
|
|
|
**Packaging**:
|
|
- Arch Linux PKGBUILD
|
|
- Gentoo ebuild
|
|
- Generic tarball
|
|
|
|
**Installation**:
|
|
```bash
|
|
meson setup build
|
|
ninja -C build
|
|
sudo ninja -C build install
|
|
```
|
|
|
|
Module location: `/usr/lib64/enlightenment/modules/iwd/`
|
|
|
|
**Verification**: Clean install works, module appears in E module list
|
|
|
|
---
|
|
|
|
## Directory Structure
|
|
|
|
```
|
|
/home/nemunaire/workspace/eiwd/
|
|
├── meson.build # Root build config
|
|
├── meson_options.txt
|
|
├── README.md
|
|
├── INSTALL.md
|
|
├── LICENSE
|
|
├── data/
|
|
│ ├── meson.build
|
|
│ ├── module.desktop # Module metadata
|
|
│ ├── theme.edc # Edje theme
|
|
│ └── icons/ # SVG/PNG icons
|
|
├── po/ # i18n
|
|
│ ├── POTFILES.in
|
|
│ └── eiwd.pot
|
|
├── src/
|
|
│ ├── meson.build
|
|
│ ├── e_mod_main.c # Module entry point
|
|
│ ├── e_mod_main.h
|
|
│ ├── e_mod_config.c # Config dialog
|
|
│ ├── e_mod_gadget.c # Shelf icon
|
|
│ ├── e_mod_popup.c # Popup window
|
|
│ ├── iwd/
|
|
│ │ ├── iwd_dbus.c # D-Bus connection
|
|
│ │ ├── iwd_dbus.h
|
|
│ │ ├── iwd_device.c # Device abstraction
|
|
│ │ ├── iwd_device.h
|
|
│ │ ├── iwd_network.c # Network abstraction
|
|
│ │ ├── iwd_network.h
|
|
│ │ ├── iwd_agent.c # Agent implementation
|
|
│ │ ├── iwd_agent.h
|
|
│ │ ├── iwd_state.c # State machine
|
|
│ │ └── iwd_state.h
|
|
│ └── ui/
|
|
│ ├── wifi_status.c # Connection status widget
|
|
│ ├── wifi_status.h
|
|
│ ├── wifi_list.c # Network list widget
|
|
│ ├── wifi_list.h
|
|
│ ├── wifi_auth.c # Passphrase dialog
|
|
│ └── wifi_auth.h
|
|
└── tests/
|
|
├── meson.build
|
|
└── test_network.c
|
|
```
|
|
|
|
---
|
|
|
|
## Critical Files (Implementation Order)
|
|
|
|
1. **`meson.build`** - Build system foundation
|
|
2. **`src/e_mod_main.c`** - Module lifecycle (init/shutdown/save)
|
|
3. **`src/iwd/iwd_dbus.c`** - D-Bus connection to iwd
|
|
4. **`src/iwd/iwd_agent.c`** - Passphrase handling (essential for secured networks)
|
|
5. **`src/e_mod_gadget.c`** - Primary user interface (shelf icon)
|
|
|
|
---
|
|
|
|
## Key Technical Decisions
|
|
|
|
**Build System**: Meson (modern, used by newer E modules)
|
|
**UI Framework**: Elementary widgets (EFL/Enlightenment standard)
|
|
**D-Bus Library**: eldbus (EFL integration, async)
|
|
**State Management**: Signal-driven (no polling)
|
|
**Security**: Never log passphrases, rely on iwd for credential storage
|
|
|
|
---
|
|
|
|
## Performance Targets
|
|
|
|
- Startup: < 100ms
|
|
- Popup open: < 200ms
|
|
- Network scan: < 2s
|
|
- Memory footprint: < 5 MB
|
|
- No periodic polling (signal-driven only)
|
|
|
|
---
|
|
|
|
## Dependencies
|
|
|
|
**Build**:
|
|
- meson >= 0.56
|
|
- ninja
|
|
- gcc/clang
|
|
- pkg-config
|
|
- edje_cc
|
|
|
|
**Runtime**:
|
|
- enlightenment >= 0.25
|
|
- efl (elementary, eldbus, ecore, evas, edje, eina)
|
|
- iwd >= 1.0
|
|
- dbus
|
|
|
|
**Optional**:
|
|
- polkit (permissions management)
|
|
|
|
---
|
|
|
|
## Security Considerations
|
|
|
|
1. **Never log passphrases** - No debug output of credentials
|
|
2. **Clear sensitive data** - memset passphrases after use
|
|
3. **D-Bus only** - No plaintext credential storage in module
|
|
4. **Polkit enforcement** - Respect system authorization policies
|
|
5. **Validate D-Bus params** - Don't trust all incoming data
|
|
|
|
---
|
|
|
|
## Known Limitations
|
|
|
|
- No VPN support (out of scope per PRD)
|
|
- No ethernet management (iwd is Wi-Fi only)
|
|
- Basic EAP UI (username/password only, no advanced cert config)
|
|
- No WPS support in initial version
|
|
|
|
---
|
|
|
|
## Success Criteria
|
|
|
|
- Module loads and appears in Enlightenment module list
|
|
- Can scan for networks and display them sorted by known + signal
|
|
- Can connect to open and WPA2/WPA3 networks with passphrase
|
|
- Can disconnect and forget networks
|
|
- Handles iwd daemon restart gracefully
|
|
- No UI freezes during scan/connect operations
|
|
- Memory leak free (Valgrind clean)
|
|
- Feature parity with econnman Wi-Fi functionality
|