Move the on_mouse_wheel handler before the cursor.is_over(bounds)
guard. The panel's nested compositor only routes axis events to the
applet surface when the pointer is over it, making the bounds check
redundant for scroll events. This fixes scroll-to-adjust-volume not
working on the audio applet after a fresh login, when the cursor
coordinates sent by the panel may not match the applet's surface-local
coordinate space.
Avec Wayland axis_v120 (scroll haute-résolution sur souris HID modernes),
un cran physique génère 5–8 events ScrollDelta::Pixels (~15–20px chacun).
L'ancien code passait chaque sub-event par .signum() puis -1/+1 à sink_volume,
donc un seul cran physique faisait varier le volume de 5 à 40% — résultat :
scroll up sur l'icône audio panel / dock coupait le son si le volume était
déjà bas.
Fix : thread_local accumulator des deltas Pixels, émission seulement
au passage du seuil de 15px par cran logique. Lines (souris classique
sans axis_v120) reste proportionnel y * WHEEL_STEP. round() au lieu de
truncation finale pour ne pas perdre les fractions de pourcent.
Leyoda 2026 - GPLv3
Replace 3 panicking unwrap() in cosmic-app-list/wayland_handler.rs
(event loop dispatch + 2 conn.flush in screencopy) with logged
errors that break/return None instead.
Wrap cosmic-applets/main.rs entry point in panic::catch_unwind to
catch panics propagating from libcosmic/iced/winit (which we cannot
patch locally without forking) when the COSMIC compositor closes
the Wayland connection at logout. This eliminates the cascade of
~12 SIGABRT coredumps observed at session shutdown.
Panic strategy is unwind (default), catch_unwind is sound here.
Leyoda 2026 – GPLv3
Inter-icon hover changes were snapping because icon_scale_for read the
hovered icon's real rectangle directly. This adds a small animation
layer so the bell center lerps toward the target and the whole effect
fades in/out at the dock's edges.
CosmicAppList gains three fields:
- anim_hover_center: Option<(f32, f32)> — virtual cursor position,
chases the hovered icon's center across ticks.
- anim_hover_intensity: f32 (0..1) — global fade-in/out of the
fisheye. Target 1.0 while a dock icon is hovered, 0.0 otherwise.
- anim_last_tick: Option<Instant> — for dt-based exponential smoothing
(time-constant tau = 60ms, ~99% of target reached in ~120ms).
A new Message::AnimTick(Instant) is emitted at ~60 fps by a
conditional iced::time::every subscription — only active when the
pointer is over a dock icon OR intensity hasn't faded back to ~0 yet,
so the panel stays idle when no one is hovering the dock.
icon_scale_for now reads anim_hover_center instead of rectangles[hovered]
and multiplies the bell's peak by anim_hover_intensity. Behaviour:
- Pointer slides A → B: bell glides continuously, both icons animate.
- Pointer enters dock: icons inflate smoothly over ~120 ms.
- Pointer leaves dock: icons deflate smoothly over ~120 ms.
Fallback paths (first frame, missing rectangles) still respond
instantly so the feature never looks 'stuck' before the animation
kicks in.
Replaces the binary 1.3× hover with a true gaussian bell curve — the
hovered icon still peaks at ~1.35×, but the ±1 neighbours also bulge
noticeably, ±2 a bit, and ±3+ relax to 1.0×. Footprint ~5 icons wide,
matching the macOS Dock fisheye feel.
Implementation in fn icon_scale_for(id):
- Reads the hovered icon's and the current icon's bounds from
self.rectangles (already populated by the existing RectangleTracker
subscription — no new plumbing).
- Distance = |this_center - hovered_center| along the panel's long axis
(horizontal for Top/Bottom anchors, vertical for Left/Right).
- sigma = hovered_extent * 1.4 so the bell's half-width matches one
icon width (neighbors clearly pulled, far icons untouched).
- scale = 1.0 + PEAK * exp(-(d/sigma)²) with PEAK = 0.35.
- Falls back to binary 1.35×/1.0× when rectangle data isn't populated
yet (first render / resize) — visibly responsive even before the
tracker catches up.
No widget signature changes vs v1, just a smarter formula. All five
as_icon call sites already pass the result of icon_scale_for so this
update propagates everywhere.
Still on the TODO list: smooth animation (b). Right now icon→icon
transitions snap instantly; a smoothed_hover_center + tick subscription
would lerp it. Deferred to a follow-up commit.
First pass at the signature macOS Dock effect — the icon under the
pointer grows, adjacent icons stay at base size. Full fisheye (smooth
bell-curve scaling on neighbors) can be a later iteration.
Changes in cosmic-app-list/src/app.rs:
- CosmicAppList gains a hovered_dock_item: Option<DockItemId>
auto-initialized to None via #[derive(Default)].
- New Message::DockItemHover(Option<DockItemId>) handled in update()
by just writing the field; view() then reads it to decide scale.
- DockItem::as_icon gains an icon_scale: f32 parameter. Inside it the
cosmic_icon width/height = (base_icon_size * icon_scale) clamped
to u16; indicator dot and other surrounding layout stay at base
size so only the icon visually bulges.
- New App::icon_scale_for(id) helper: 1.3 if Some(id) == hovered,
1.0 otherwise. Single place to tune the magnification factor.
- The two main dock rows (favorites + filtered_active_list) wrap
their rendered applet_tooltip in widget::mouse_area with
on_enter(DockItemHover(Some(id))) / on_exit(DockItemHover(None))
and call icon_scale_for before rendering.
- The three remaining as_icon call sites (DnD preview, favorites
overflow popup, active overflow popup) pass icon_scale = 1.0 —
hover magnification on those surfaces would look jittery and isn't
needed anyway.
Build: cargo build --release -p cosmic-app-list (≈ 7s). Binary
installed at /usr/local/bin/cosmic-app-list, backup kept as
.pre-magnification.
StatusNotifierItems can expose a Scroll(int delta, string orientation) method for tray hosts to call when the user wheels over an item. The status-area applet handled activation and context menus, but did not forward wheel events to that method.
Track the hovered tray item only while the pointer is over an icon, ignore wheel events already captured by widgets, accumulate fine-grained wheel deltas into discrete scroll steps, and call Scroll on the item proxy. Add unit coverage for the delta/orientation mapping and pixel accumulation.
Signed-off-by: William Fish <william.michael.fish@gmail.com>
`cosmic-applet-network` listed every connection from `nm.list_saved_connections()` in the VPN dropdown, including the in-memory-only profiles NetworkManager auto-generates for externally-managed interfaces (e.g. a `wg-quick@wg0.service` tunnel). Toggling such an "assumed" connection off deletes it from NM — it was never persisted — leaving a dead toggle with no way back through the applet or `nmcli con up`.
Skip connections flagged `unsaved` (in-memory only) at the `load_vpns()` site so they no longer get a togglable entry. The active-connections section still shows the interface as connected (read-only). One-line change in `cosmic-applet-network/src/app.rs`.
## Test plan
- Built on Pop!_OS and ran the patched `cosmic-applet-network`: with `wg-quick@wg0` up and NM tracking `wg0` as connected-externally, the VPN dropdown no longer shows the destructive `wg0` toggle; the active-connections section still shows `wg0`; Wi-Fi toggling is unaffected.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>