Skip to content

refactor(services): move upower into ashell-services - #993

Draft
MalpenZibo wants to merge 8 commits into
refactor/ashell-services-cratefrom
refactor/upower-ashell-services
Draft

MalpenZibo wants to merge 8 commits into
refactor/ashell-services-cratefrom
refactor/upower-ashell-services

Conversation

@MalpenZibo

@MalpenZibo MalpenZibo commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Stacked on #988: review and merge that one first. This PR only adds the last commit.

@MalpenZibo
MalpenZibo marked this pull request as draft September 30, 2026 18:53
@romanstingler

romanstingler commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

you wanna have this for 0.11.0 ?

I will try to find some time for review tomorrow evening.

@MalpenZibo

Copy link
Copy Markdown
Owner Author

Nono, I Plan to release a 0.10.1 with what we currently have maybe tomorrow.

This will be part of a next release (maybe December). Anyway there's no hurry

@romanstingler

romanstingler commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

very good, I also want to take a deeper look into some quirks that people mentioned in the past for the next 0.11.0 release.
I think the important PRs are already merged into this release.

The question is, should we make another release in between and try to add the PRs/features still open (that make sense) and some cleanups. I Still have a few things that I started a longer time ago but I am always distracted with other stuff that comes up :)

image image

I think we did a good job adding stuff that people wanted.
And also since May we close more issues than are opened.

… crate

Turn the repo into a Cargo workspace and add crates/ashell-services, a
library for services that do not depend on iced or any other UI
toolkit, so the same code can back other UIs.

The crate imposes no service trait. Bluetooth is exposed as a cloneable
handle with async command methods, a data() snapshot and an updates()
stream that yields a fresh snapshot on every change. Each service sits
behind a cargo feature of the same name, with no default features.

src/services/bluetooth.rs wraps that API into the iced ReadOnlyService
and Service traits and keeps the UI policy (optimistic toggle, 15s
discovery, refresh after each command), so the settings module and the
network service are unchanged.

CI and make check now lint the whole workspace.
The soft-block check and the /dev/rfkill watch lived on the bluetooth
service even though the NetworkManager and IWD backends also use them to
derive airplane mode. Move them to an rfkill utility module behind their
own feature, enabled by bluetooth, so network no longer depends on the
bluetooth service.
Describe the workspace layout, the trait-free service API and the iced
glue in src/services, the per-service cargo features and the rfkill
helpers, and point the bluetooth D-Bus references at the new crate.
Both the iced glue and a guido consumer had to duplicate the command
enum, the dispatch to the handle methods, the toggle and discovery
policy and a refresh after every command. Move all of that into the
crate so glue code only forwards commands and publishes snapshots.

- BluetoothCommand and Bluetooth::execute live in the crate. Toggle
  reads the real adapter and rfkill state instead of trusting a UI copy,
  and StartDiscovery stops on its own after 15 seconds.
- updates() yields the current state as soon as it is subscribed, which
  also closes the gap between the initial read and the subscription.
- updates() is complete: it also watches Paired and Alias, and rebuilds
  the per-device watchers when devices are added or removed, so devices
  that appear later are tracked too. Commands no longer refresh by hand.
- Property streams yield their current value first; skip it so each
  (re)subscription reads a single snapshot instead of one per property.
- Devices are sorted by name, and the data types derive PartialEq and
  Default, so reactive UIs can diff snapshots without spurious updates.
changes() read every device's properties through devices() just to get
their paths. A device removed between GetManagedObjects and its property
read made BlueZ answer UnknownObject, which failed the whole rebuild and
ended the updates stream for good. This happens routinely while
discovery is on, as BlueZ drops stale scanned devices.

changes() now takes the device paths and their Battery1 presence from a
single GetManagedObjects call and skips a device whose proxy cannot be
built. devices() also skips vanished devices instead of failing the
snapshot.

When org.bluez has no owner the stream yields the unavailable state and
waits for NameOwnerChanged, instead of calling into org.bluez and
triggering bus activation. A bluez restart while listening is treated as
a topology change. Other rebuild failures are retried after 5 seconds
instead of ending the stream.

execute() builds the BlueZ proxy once per command, which removes the
public wrapper methods. The unused data() method and full feature are
dropped, and the per-rebuild log moves to debug.
Run the Nix build when only crates/ changes, update the documented lint
commands to the workspace-wide ones, and fix the bluetooth entry in the
project layout and the Service trait signature.
The UPower service joins bluetooth in the UI-agnostic crate, behind a
new upower feature: plain UPowerData snapshots, a cloneable UPower
handle with execute(UPowerCommand), and an updates() stream that yields
the current state and a fresh snapshot on every change. Commands now
read the current profile and charge threshold from D-Bus instead of the
cached UI state, and their effect arrives through the stream. Devices
added or removed at runtime now also get their property changes
watched.

The stream follows the bluetooth one: a device that vanishes during
enumeration is skipped instead of failing the rebuild, the unavailable
state is emitted while org.freedesktop.UPower has no owner, and a
daemon restart triggers a rebuild.

The stream throttle moves to the crate as a shared helper module, and
an optional serde feature derives Deserialize on PeripheralDeviceKind
for the config.

Icons, indicator state and the throttled keyboard backlight writer with
its optimistic Remote value stay in ashell, in the iced glue at
src/services/upower.rs.
@MalpenZibo
MalpenZibo force-pushed the refactor/ashell-services-crate branch from 2ef4f91 to 3d0b977 Compare October 2, 2026 17:21
@MalpenZibo
MalpenZibo force-pushed the refactor/upower-ashell-services branch from 93a7acc to ad93bb4 Compare October 2, 2026 17:21
@MalpenZibo
MalpenZibo force-pushed the refactor/ashell-services-crate branch 4 times, most recently from 24bd8d8 to 39e2c44 Compare October 8, 2026 08:55

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants