1339 Commits
Author SHA1 Message Date
Vladimir Kostelei c6c40dbced fix: fingerprint lid open (#3448)
* lock: keep the fingerprint reader usable across suspend

The reader stopped responding after the lid was closed and opened, after a long
idle period, and after suspend.

The shell held a PAM session for as long as the screen was locked, so a suspend
always landed on a running verify. fprintd then suspends the device under the
verify, pam_fprintd's ReleaseDevice fails with "device is still busy", and the
claim is never released, so every later Claim fails until fprintd restarts. The
reader is now released when the monitors blank and armed again when they come
back, so a suspend has nothing left to wedge.

The PAM profile drops to max-tries=1 and sets an explicit timeout. pam_fprintd
only counts a wrong finger, so one finished session is now one wrong scan and
maxFprintTries means the number of scans it names rather than five times that.
A timeout expiry arrives as PamResult.Error, exactly like a device fault, so a
session that ran at least as long as the configured timeout is treated as a
planned renewal instead of spending the error budget and painting an error.

A suspend that still lands while the screen is on wedges as before. Recovery now
waits out fprintd's idle timeout instead of climbing to it, which brings the
reader back about 37 seconds after resume instead of about 98.

SessionService gains lidOpened from UPower, because logind can ignore the lid on
AC and resume alone is not enough. The lock PAM state machine is fixed alongside:
PamResult.Failed was dropped, a pending retry outlived the contexts that owned
it, and an availability check reset the wrong-scan counter.

* lock: time the fingerprint session from the verify, not the claim

pam_fprintd's timeout runs from the verify, but the session age was measured
from start(), which folds the claim into it. A slow claim plus a verify that
failed before its own timeout could add up past the timeout and be taken for a
planned renewal, skipping the backoff. A session that never reached a verify had
the same problem.

The age now starts at the message pam_fprintd sends when the verify begins, so a
session that never verified can never qualify as an expiry, and a slow claim no
longer ages a fault. The message is translated and quickshell clears it before
completed, so only its timing is used, never its text.

That message arrives after pam_fprintd has already armed its deadline, because
VerifyStart is asynchronous, so the age read here runs short of the real timeout
and a slack makes it up. The bias is deliberate. A fault misread as a timeout
costs one extra retry, while a timeout misread as a fault parks the reader behind
a backoff that grows to a minute, which on an idle lock screen would leave it
unusable most of the time.

Also corrects the comment that claimed a timeout is reported without a message.

---------

(cherry picked from commit d7074a53eb)
2026-10-07 13:05:09 -04:00
LemonMon fb002d1977 fix: stabilize tray item key to prevent position jumps on property changes (#3386)
* fix: keep tray order stable when tooltipTitle changes dynamically

Revert the earlier simplistic key approach: keep getTrayItemKey()
unchanged (id::tooltipTitle) so duplicate-id disambiguation (#1542)
is preserved and persisted id::tooltipTitle entries keep matching.

Instead make persisted-key lookups tolerant of dynamic tooltipTitle:
resolveOrderIndex() in sortByPreferredOrder() does exact match first,
falling back to prefix matching an id::* entry only when the id has a
single instance. findSavedTrayKey()/isTrayIdHidden() replace direct
SessionData.isHiddenTrayId() calls and showTrayId() now receives the
actual saved key.

Prefix fallback is gated by trayItemCountForId() to single-instance
ids only, so multiple items sharing an id always match exactly and
hiding/ordering one never affects the others.

* fix: bail on ambiguous saved tray keys in fallback

* tray: use occurrence index as stable key, add one-time session migration

* tray: pin stable key per item instance so it never flips when siblings come and go

* tray: assign unique per-id sequential keys to avoid collision after sibling exit

* tray: reuse free key slots so a restarted singleton keeps its plain id

(cherry picked from commit 60342b7416)
2026-10-07 13:01:06 -04:00
Huỳnh Thiện Lộc b6fee3a98f fix(island): avoid bottom clipping in media expanded sheet (#3593)
(cherry picked from commit 0717908d53)
2026-10-07 12:58:37 -04:00
Huỳnh Thiện Lộc d06fcccff9 fix(notepad): hide placeholder during IME composition (#3646)
(cherry picked from commit 340f2d179c)
2026-10-07 12:58:37 -04:00
Marlon Kranz d9cfeded47 fix(lock): show the lock screen on every display when none is selected (#3666)
With two or more screens connected and none of them in the lock screen
display list (a laptop docked at a different desk), every surface was
inactive and no password field rendered, so the only way out was a
TTY. getFilteredScreens only falls back to all screens with
showOnLastDisplay and exactly one screen, which the lock screen picker
never sets. Treat an empty result as all screens, the same as the
default "all" preference.

(cherry picked from commit 6a320399c9)
2026-10-07 12:58:37 -04:00
bbedward ce2ec80d80 bar: detect touchpads by scroll phase instead of pixelDelta 2026-10-07 12:34:11 -04:00
bbedward 097de493bb displayconfig: fix custom scale option 2026-09-17 10:33:09 -04:00
Domen Kožar fd0564a3ec tray: use available width for menu labels (#3456)
(cherry picked from commit 1bf35426ea)
2026-09-17 09:43:22 -04:00
Marlon Kranz 07f8675a7b fix(frame): keep launcher edge-hover on the Top layer (#3453)
Opening the launcher by hovering the frame edge requested the Overlay
layer via CompositorService.framePeerSurfacesUseOverlayForScreen(),
which resolves to whether the frame is configured for the screen and
is true in normal use. DankLauncherV2ModalConnected's
frameOwnsConnectedChrome requires the Top layer, so the overlay
request silently dropped connected-chrome anchoring: the launcher
opened dead-centered with a different animation instead of emerging
from the configured frame side.

The keybind/bar-button path already opens on the Top layer by passing
no overlay argument. The edge-hover trigger only runs in connected
frame mode to begin with (gated by usesConnectedFrameChromeForScreen
in this file's own eligible check), so there's no case where it needs
standalone/overlay behavior. Match the keybind path.

(cherry picked from commit 579d6f7b5c)
2026-09-17 09:41:33 -04:00
Alexander cab2a1a3bc dock: fix overview visibility on niri (#3460)
(cherry picked from commit 81d5962650)
2026-09-17 09:41:21 -04:00
Giacomo Di Clerico fde2181c3b tailscale: handle profile switches and bus updates reactively (#3427)
* tailscale: handle profile switches and bus updates reactively

* tailscale: address review feedback on test coverage and dead code

(cherry picked from commit 218f7f752f)
2026-09-15 16:46:47 -04:00
Harsh Kumar a5ffd18596 display config: read live layout from hyprland instead of the cached wlr snapshot (#3418)
(cherry picked from commit d7b5812561)
2026-09-15 16:46:47 -04:00
Timofey d3a02f6342 hyprland: use focusedMonitor instead of focusedWorkspace.monitor (#3424)
Hyprland's workspace refactor (hyprwm/Hyprland#16140) broke
Hyprland.focusedWorkspace.monitor as a way to find the focused screen
(quickshell-mirror/quickshell#1119). Quickshell already exposes
Hyprland.focusedMonitor directly, so read the monitor from there

(cherry picked from commit 05c807b7cd)
2026-09-15 16:46:47 -04:00
Mario Mohar 1b34aa0ce1 fix(battery): report when no charge threshold exists instead of faking success (#3385)
* fix(battery): report when no charge threshold exists instead of faking success

* fix(battery): hide the charge limit controls when there is no battery

Follow-up to the review on #3385: the new explanation showed on
desktops and VMs with no battery at all, where it reads as a fault
report about hardware the machine was never going to have.

Both the explanation and the apply button now require
BatteryService.batteryAvailable. Hiding the button there is the same
point the pull request makes elsewhere: offering a control that cannot
work is what produced the false success in the first place. A machine
without a battery has no charge threshold to write to, so the limit was
never applicable.

BatteryService.batteryAvailable is already the gate used twice in this
file for the same reason.

(cherry picked from commit 6b50696b8a)
2026-09-15 16:46:47 -04:00
Mario Mohar b69496dbcd fix(settings): size the plugin update spinner to fit its row (#3383)
(cherry picked from commit cf74c10561)
2026-09-15 16:46:46 -04:00
purian23 12f7675950 refactor(island): add island satellite hover option
fixes #3296
port 1.6

(cherry picked from commit 60675ecb39)
2026-09-10 03:36:41 +00:00
Zoey Bauer 4015f634c4 add support for shelly (#3367)
* add support for shelly

* fixed terminal failure

* updated to have it not allow adding ignore aur

* updated error strings

* Fixed label

port 1.6

(cherry picked from commit 8fe918ff24)
2026-09-08 15:50:35 +00:00
bbedward b2d1ec6690 systray: dont wrap context menu title
port 1.6

(cherry picked from commit 2bf2754ad2)
2026-09-08 14:19:25 +00:00
BB 94710cf643 feat: support for Aqueous Compositor (#3357)
* updated dank to support aqueous

* further updates

* aqueous support work

* updated to support workspace options better in aqueous

* added blur to dms shell for aqueous

* added keybinding update

* remove unneeded blur

* clean up per claud review

* swapped to ipc

* aqueous: move IPC integration to QML, delete test fixtures (since we
dont have a QML test structure even setup), delete in-repo docs

* fix staticcheck

* aqueous: consolidate more aqueous specific stuff

* add aqueous logo

---------

Co-authored-by: Zoey <[email protected]>
(cherry picked from commit b9365610c8)
2026-09-08 09:23:54 -04:00
bbedward 40a0eb6841 workspace: keep hit area out of adjacent spacers
fixes #3360
port 1.6

(cherry picked from commit fb07a91108)
2026-09-08 01:19:27 +00:00
bbedward 6261e580aa bar: refresh blur region after widget layout settles
ref #3348
port 1.6

(cherry picked from commit 62ad4c2cb7)
2026-09-06 17:54:19 +00:00
bbedward e8a755b85d controlcenter: release dgop refs while the popout is closed
ref #3349

(cherry picked from commit 654c6dce8f)
2026-09-06 13:40:26 -04:00
bbedward 6713f05e02 audio: add output card selection
port 1.6

(cherry picked from commit 8188f53da5)
2026-09-06 17:15:06 +00:00
bbedward 5d39702136 lock: keep the password cursor inside the field and follow it through overflow and wrapped reveals
fixes #3319
port 1.6

(cherry picked from commit 5baef07048)
2026-09-05 16:26:30 +00:00
bbedward 166b82df1b network: reject weak hotspot passwords before handing them to NetworkManager
fixes #3318
port 1.6

(cherry picked from commit f402731ef2)
2026-09-05 16:21:54 +00:00
bbedward bca1466162 dash, notifications, island: fix calendar banner overflow, expand chevron, and player row clipping
fixes #3300
fixes #3301
fixes #3317
port 1.6

(cherry picked from commit 59f6f1fa71)
2026-09-05 16:21:52 +00:00
bbedward a1b51b191f bar: focus workspace icons on any workspace and wire island overview loader
fixes #3309
fixes #3310

port 1.6

(cherry picked from commit 3d6e45f430)
2026-09-05 15:40:15 +00:00
bbedward 5defc26929 display config: judge profile outputs by live heads, not stored make/model
fixes #3306
port 1.6

(cherry picked from commit 85bc7604c2)
2026-09-05 15:40:12 +00:00
Adolfo Ochagavía cb85620777 Fix repeated day in calendar (#3302)
Root cause: we were creating a `Date` that did not exist in my timezone
(Santiago, Chile) because of DST. The JS engine decided to pick the
previous day, so I ended up with two times 5 September.

Fix: introduce a `DateOnly` object that internally uses UTC (to prevent
DST issues). Other parts of the system still use `Date`, which
probably should be refactored to use `DateOnly` as well (maybe in an
upcoming PR?). In the meantime, we provide a function to export a
`DateOnly` as a `Date`, using noon as the time instead of midnight
(because there are no DST changes at noon AFAIK).

We tested this manually (see the attached screenshots), but didn't find
a suitable place for automated tests.

port 1.6

(cherry picked from commit e4793327b8)
2026-09-04 23:42:17 +00:00
purian23 faf25e98a5 feat(island): vertical orientation layout management support
Port 1.6

(cherry picked from commit e18931353b)
2026-09-04 21:57:39 +00:00
bbedward 19a56d1835 clock: align the horizontal time block to whole pixels
fixes #3291
port 1.6

(cherry picked from commit fbffa410af)
2026-09-04 16:02:53 +00:00
Huỳnh Thiện Lộc acca7fae68 fix(dash): dim today button when on current month (#3294)
* fix(dash): dim today button when on current month and hide tooltip on click

* fix(dash): use Theme.shortDuration for calendar today button opacity animation

* refactor(dash): use standard DankActionButton tooltipText for calendar today button

* chore(dash): remove unused todayButton id

* fix(dash): allow returning to today when another day in current month is selected

(cherry picked from commit 07d8e28668)
2026-09-04 10:38:44 -04:00
bbedward a478c27fd0 bar: make the global shadow toggles authoritative
(cherry picked from commit 4e2afb53cc)
2026-09-04 10:38:37 -04:00
bbedward 344c1e610c theme: write desktop settings through dconf instead of gsettings
fixes #3280
port 1.6

(cherry picked from commit a665ba8ca5)
2026-09-04 14:37:58 +00:00
枫莹 6ed79d06df fix(plugins): use plugin ids for management actions (#3284)
(cherry picked from commit 433b13cb0e)
2026-09-04 09:51:29 -04:00
purian23 700f43a194 feat(island): allow hiding clock or date options in compact pill
Port 1.6

(cherry picked from commit c1f1da1d26)
2026-09-04 04:47:35 +00:00
bbedward 6a4ce613bb colorpicker/popout: add instant-close machinery for eye dropper 2026-09-03 12:51:15 -04:00
Mario Moharandbbedward 5142d576f5 fix(bar): centre widget content on whole pixels (#3263)
* fix(bar): keep widget content on whole pixels

Bar widgets centre their content inside a box of
widgetThickness - horizontalPadding * 2, and Qt rounds the offset of a
centred anchor to whole pixels. When the content and that box have
different parity the exact offset falls on a half pixel, Qt rounds it
away from zero and the content renders half a pixel above the centre.
Widgets drawn from rectangles, such as the workspace switcher, compute
their own snapped height and stay exactly centred, which is why they
look right next to everything else in #3074.

With the stock configuration this is the normal case: the bar is 40 px,
the box is 14 px and barIconSize returns round((40 / 48) * 18) = 15.

Two sizes now round to whole pairs of pixels. The icon size, so that it
matches the parity of the box, and widgetThickness, because the box
inherits its parity from there (the padding is doubled, so it never
changes it). Going through every innerPadding from 0 to 16, nine of the
seventeen configurations currently put the icon on a half pixel and none
of them do afterwards. The 48 px default bar is untouched, the sizes
that change do so by one pixel.

Measured in a nested Hyprland at scale 1, ink centroid of the widget
content relative to the centre of its pill, before and after:

  launcher      -0.50   +0.00
  weather       -0.81   -0.52
  clipboard     -1.49   -0.93
  notifications +0.03   +0.46
  battery       -0.63   -0.49
  bluetooth     -0.53   -0.03

Every icon moves down by half a pixel. What remains matches the ink
asymmetry of the individual glyphs, measured separately at an exact
position, and is not a placement error.

Two things this does not cover. On a fractional or HiDPI scale
horizontalPadding can land on a half pixel, which puts the box back
between the grid lines, and a text only widget such as the clock has a
line box of 15 px at the default font size, which cannot sit exactly on
the centre of a 28 px pill no matter how it is rounded.

Closes #3074

* fix(bar): give bar text a line box that can be centred

A widget without an icon is centred as one line box, and the same parity
rule applies to it as to the icon in the commit before this one. At
fontSizeSmall the line box of the bar font is 15 px tall, so on a 28 px
pill it cannot sit on the centre no matter which way the offset is
rounded, and the clock reads about half a pixel high next to everything
else. One step up the box is 16 px and it lands on the grid.

Only the branch the standard bar uses changes. The 0.9 branch below a
scale of 0.75 already comes out at 14 px, and the fontSizeMedium branch
above 1.25 is left alone because there the next even box is two steps
away, which would be a bigger change than this is worth.

Same session and same measurement as the previous commit, ink centroid
of the widget content relative to the centre of its pill:

  clock and date  -0.58   +0.05
  battery         -0.63   -0.05
  weather         -0.82   -0.28

The bar font goes from 12 px to 13 px, which is the visible part of this
and the reason it is a separate commit. It can be dropped without
touching the icon fix.

* bar: snap widget thickness to even device pixels and pick text sizes by line box parity

* bar: snap bar thickness to even so the pill centres on whole pixels

* bar: share the bar thickness formula so dock, osd and popouts stay in step

* dock: read the bar clearance at the compositor screen scale

---------

Co-authored-by: bbedward <[email protected]>
2026-09-03 12:13:09 -04:00
bbedward 592ca3ee8f island: follow island opacity in every state and drop covered widget blur 2026-09-03 10:40:34 -04:00
Marlon Kranz 4693178345 feat(theme): add a selectable source color mode for wallpaper palettes (#3020)
* feat(theme): add a selectable source color mode for wallpaper palettes

DMS always seeds the palette from matugen's most dominant candidate
(--source-color-index 0, hardcoded at both call sites). When a large
muted region outvotes a smaller vivid one, a visibly warm wallpaper
produces a cold palette: one image here goes to #8ad0ee where the warm
subject is at hue 46.

Adds a Source Color setting with seven values. Dominant is the default
and is byte-identical to today. Colorful is computed in Go before
matugen runs: quantize the image (Wu for the starting clusters, then a
weighted k-means in Lab), score the result the way caelestia-cli does,
and hand matugen the resulting hex. Its scoring walks a chroma/tone bar
down from 20 until something clears it, which biases the pick toward a
colorful, well-lit color rather than whichever muted color covers the
most pixels. The remaining five map to matugen's --prefer.

- core/internal/matugen/sourcecolor.go: extraction, scoring, and the
  one helper both matugen call sites now share
- buildOnce resolves the seed once, before the StockColors branch, so
  the dry run and the real run cannot disagree about it
- extraction failure logs a warning and falls through to matugen's own
  extraction; it never fails a theme build
- --prefer arrived in matugen 4.1, so it is gated separately from the
  existing isV4 check; on 4.0.x those five modes degrade to the
  dominant color instead of aborting on an unknown argument
- --source-mode on generate and queue, plus sourceMode on the socket
  handler
- Source Color dropdown in Theme & Colors, defaulting to Dominant

Adds github.com/Nadim147c/material/v3 (Apache-2.0, no dependencies) for
HCT conversions, Wu quantization and the dislike analyzer. Its
QuantizeCelebi is not used: it returns after one unconverged iteration
and its Lab.DistanceSquared is a dot product rather than a distance, so
it collapses most of an image into a single cluster.

* fix(theme): address review feedback on source color mode

Two points from review on #3020.

The quantize comment pointed at a FOLLOWUPS file that does not exist in
this repository. Replaced the reference with the measurement it was
standing in for, so the claim is self-contained.

setMatugenSourceMode called Theme.generateSystemThemesFromCurrentTheme()
directly on top of the regenSystemThemes onChange hook that Spec.set
already dispatches. Both feed a 100ms debounce so it was one generation
either way, but the direct call was redundant and is gone.

* fix(theme): keep {{image}} resolvable in colorful mode

Colorful resolves the seed itself and calls matugen with a hex source, which
leaves matugen's {{image}} unset: the builtin pywalfox template and any user
template using the keyword render the literal string "Null".

Pass the wallpaper path alongside dank16 in --import-json-string, as suggested
in review, so those templates keep working unedited. The path is made absolute
to match what matugen renders for {{image}} in the other modes.

* fix(theme): cut translator terms on the source color dropdown

Per-mode descriptions were seven of the fifteen new terms this branch adds,
and five of them differed by a single adjective. Drop them: the dropdown row
already describes what the setting does, and the docs cover each mode.
2026-09-03 09:07:21 -04:00
purian23 ab1e57dda5 refactor(media): re-add wallpaper blur to island media & misc tweaks
- New Wallpaper on/off toggle in the Media Player tab for Dashboard and Island Media
2026-09-03 01:28:05 -04:00
purian23 1d2ba798b0 fix(widgets): update island drag & drop targets 2026-09-03 00:02:47 -04:00
purian23 78e3308f40 feat(battery): circle battery option per/bar instance & theme/step colors
- New settings located in Bar > Widgets and Island > Appearance
- Theme & Step Colors located in Bar > Appearance
2026-09-02 23:14:02 -04:00
bbedward c6c14576eb bar: support multiple bars in island and frame modes 2026-09-02 19:12:49 -04:00
bbedward 0fe56c4bfa dash: align user tile right edge when weather is disabled 2026-09-02 16:49:08 -04:00
bbedward f65e5ef2f2 settings: quick simplification and cleanup prior to 1.6
the full overhaul/redesign will come later
2026-09-02 16:20:16 -04:00
purian23 81cbcef3bc refactor(island): hide & collapse inactive activities 2026-09-02 15:42:15 -04:00
bbedward e8082ad75d island: drag and drop home face layout 2026-09-02 15:25:29 -04:00
bbedward 13fafa1dff island: simplify volume and brightness home slots 2026-09-02 14:59:43 -04:00
bbedward 6df71083ec island: redesign the separate media player variant 2026-09-02 14:47:01 -04:00