* lock: lock before sleep when the command skips logind
Custom hibernate never emits PrepareForSleep, so the session stayed unlocked. Wait for the compositor lock on every sleep path, and release the delay inhibitor if that lock finished first.
* lock: release the sleep inhibitor only after lockerReady
* lock: read the sleep inhibitor under its mutex in the race test
scrollbar: interface style toggle and no scrollbars in the dash
dash: never allow scrollbars
cc: widget sheet cards, header close button and content-sized dialogs
Autostart apps (e.g. KeePassXC) that call RegisterStatusNotifierItem
before the watcher owns its name fail silently and never re-register.
Until now the recovery scan only ran on suspend/resume or watcher
owner change, so first-boot orphans were never rescued.
Schedule a one-time delayed scan when the watcher first appears.
recoverTrayItems() already deduplicates via registeredConnIDs, so this
cannot double-register apps that registered normally.
dnf lists the packages an upgrade obsoletes indented beneath it, under a
separate heading. Those rows are removals carrying their installed
version, so they were parsed as upgrades from a version to itself and
counted as pending. Skip indented rows. The heading is translated, so
matching it would only work in English.
dnf prints one row per (package, repo), so a package offered at the same
version by two enabled repos is listed twice and inflates the pending
count. Key the parse on (name.arch, version) and keep the first row.
* feat(display): per-output ICC color profiles and color temperature
Rebuild of #3388 on current master: the previous branch was cut from an
older base and reverted unrelated fixes in the gamma stack and the display
settings UI.
ICC profiles:
- core/internal/icc: ICC v2/v4 parser (TRC, LUT8/16 and parametric curves,
vcgt, description/version/color space) plus gamma ramp generation, with
synthetic coverage and optional vendor-profile tests (ICC_TEST_DIR).
- wayland manager: load iccProfiles from the compositor's DMS config dir,
build the ramp from the profile when one is set (falling back to the
temperature ramp when it is missing or unparsable), and re-apply on
output hotplug and after resume.
- ICC ramps apply while the night light schedule is disabled; outputs
without a profile keep an identity ramp.
- desc/mluc offsets are validated before slicing, so a malformed profile
returns an error instead of panicking the daemon.
Per-output temperature:
- outputTemps in the same config; SetOutputTemp accepts 1000-10000K and the
Display Config slider exposes 3000-10000K, which matters for displays
calibrated at a higher white point (e.g. a 7000K profile).
Gamma control lifecycle:
- needsControls() now keeps the controls alive for configured ICC profiles
and per-output temperatures, so toggling the night light off no longer
destroys the controls and drops the ramps.
- Re-apply paths clear the per-output dedup state instead of adding a
manager-level guard, which would have suppressed contrast-only writes and
the post-resume forced resend (#1235), and left a recreated control
without a ramp.
- Monitor sleep/disconnect still re-establishes controls when an output
comes back.
IPC / CLI / UI:
- wayland.icc.{getStatus,apply,remove,listOutputs,setTemp,getTemps}
- dms icc list | info <file> | apply <output> <file> | remove <output> | status
- Display Config output card gains a Color Profile row (browse/apply/remove
with description, version, color space and active state) and a per-output
color temperature slider, backed by Services/ICCService.qml.
Config path:
- DMSConfigDir() follows the compositor layout (niri/dms, hypr/dms,
mango/dms) via the shared compositor detection and utils.XDGConfigHome(),
replacing the hardcoded niri path in both the manager and `dms icc`.
Tests: TZ=UTC go test ./... (60 packages ok), including red/green coverage
for the icc parser bounds checks and needsControls().
* feat(icc): add `dms icc set-temp` and show per-output temps in `status`
The per-output temperature override was reachable from the Display Config
slider and from `wayland.icc.setTemp` over IPC, but not from the CLI.
- `dms icc set-temp <output> <kelvin>` (alias `setTemp`) sets a per-output
override, 1000-10000K, and 0 clears it so the output follows the night
light schedule again. Range checking matches the daemon so an invalid
value fails in the CLI instead of over IPC.
- `dms icc status` gains a Temp column (the override in K, or `schedule`),
so an override can be verified without opening the settings UI.
Verified against a running daemon: `dms icc status` reports 7000K for the
three overridden outputs and `schedule` for the remaining one.
* feat(icc): treat the per-output temperature as the profile's reference white point
The per-output temperature was documented as the white point a profile was
produced at, but an output with a profile ignored it entirely: the ramp was
generated from the profile and the temperature only applied to outputs
without one (or as the fallback when a profile failed to parse). A display
calibrated at 7000K therefore got the profile ramp, and enabling the night
light had no effect on it at all.
- `ProfileRampWithTemp` composes the profile ramp with the ratio between the
target temperature ramp and the reference ramp, so the temperature is the
white point the profile describes and the night light shifts relative to
it.
- `applyGamma` passes the night light temperature as the target, and
`noTempTarget` when the schedule is disabled, which leaves profiled
outputs at their reference white point and drives plain outputs with the
neutral ramp.
- The re-apply sentinel stays 0, so it cannot collide with an applied
temperature.
Covered by TestProfileRampWithTemp (reference == target is a no-op, warmer
and cooler targets move the expected channels).
Also: `dms icc set-temp` help text describes the reference-white-point
semantics.
* fix(icc): load the configured profiles even when controls already exist
Restoring the upstream "output returned, re-establishing controls" branch
made the registry handler establish the gamma controls before the startup
post runs, and that post returned early on `m.controlsInitialized`, so the
configured ICC profiles and per-output temperatures were never attached:
every output reported "(none)" and the night light ran with defaults until
the user re-applied a profile by hand.
- `initializeControlsAndICC` (the startup post) loads the configuration
first and only creates the controls when they are missing.
- The loading is split into `loadConfiguredICC` / `applyConfiguredICCForOutput`
so it can also run per output.
- A hotplugged output now gets its configured profile and temperature as soon
as its name is known (name handler) or when its control is created, which
also makes the "re-applies on hotplug" claim in the description true.
- After attaching, the output's dedup state is cleared so the ramp is written.
Covered by TestManager_LoadConfiguredICCWhenControlsAlreadyExist and
TestManager_AttachConfiguredICCForNamedOutput.
* fix(icc): make the per-output temperature an actual target
The per-output value was treated as the white point a profile was produced
at, which meant a display with a profile never changed when the user set a
temperature: the profile ramp was applied as measured and the value only
mattered when a night light target existed. Per-display temperatures were
therefore unusable on profiled outputs while the night light was disabled,
which is the normal state for users who want each monitor at its own value.
- `effectiveTempTarget` decides per output: a per-output override wins over
the night light schedule, the schedule applies when there is no override,
and `noTempTarget` means neither. `0` is "no override", not 0K.
- `applyGamma` composes the override on top of the profile ramp, treating the
profile as measured at 6500K (D65), and drives outputs without a profile
with the same target so both paths agree.
- `dms icc set-temp` help text and the Display Config slider description go
back to describing an independent per-output temperature.
Covered by TestEffectiveTempTarget (override wins, schedule fallback, none)
and the updated TestProfileRampWithTemp (7000K cools, 5000K warms relative to
the 6500K reference).
* feat(icc): show the profile details in Display Config
The profile row only showed the description, so there was no way to tell
which profile a display actually has applied (whitepoint, curve type, file
provenance) without leaving the settings page.
- `ICCStatus` carries the descriptive metadata: class, tone-curve kind (plus
gamma or table size), vcgt channels/entries, white point chromaticity with
a derived CCT and standard illuminant name, file size and mtime.
- `internal/icc` gains `WhitePointXY`, `WhitePointCCT` (McCamy),
`WhitePointName` (D50/D65) and `TRCKind`, all covered by tests.
- Display Config's Color Profile row gets an info button that opens
`ICCProfileInfoModal` with those fields and the profile path, alongside
the existing browse/remove actions.
- `dms icc info` reports the white point as name/xy/CCT instead of raw XYZ.
* fix(icc): keep the daemon, the state snapshot and the temp slider honest
A malformed profile could still take the daemon down, the ICC getters ran off
the wayland actor goroutine, the pushed state hid a removal, and the
per-output temperature slider dropped wheel changes.
- `internal/icc`: the tag table was sized with `uint32` arithmetic, so
`tagCount*12` wrapped (`0x15555556*12 == 8`) and a 140-byte profile passed
the bounds check, allocated ~4.3 GB and then panicked. `ParseFile` runs on
the wayland actor goroutine, which has no `recover()`, so a bad profile
persisted in `wayland.json` took the daemon down at startup. The count is now
compared against the bytes that are actually left before anything is sized
with it.
- The manager publishes an ICC snapshot (`iccStatus`/`iccTemps`) whenever the
actor changes an output's profile or temperature, and `GetICCStatus`/
`GetOutputTemps` serve that snapshot instead of ranging `m.outputs` and
reading fields the actor owns. That removes the data race reported by
`go test -race` for `dms icc status` running against a hotplug, and keeps the
per-profile `os.Stat` off the night light animation path, where it ran on
every `updateStateFromSchedule` (including each 25 K step).
- `State.ICCProfiles`/`OutputTemps` drop `omitempty`, so removing the last
profile pushes `{}` instead of omitting the key: the QML truthiness guard
then clears `ICCService.status` instead of leaving the removed profile on
screen with a green "active" dot.
- `removeOutputByRegistryName` (extracted from the registry remove handler)
deletes the `outputNames`/`outputRegNames` entries along with the output, so
a disconnected monitor stops being listed by `dms icc status`/`listOutputs`,
and a rebound `wl_output` reusing the released object ID cannot attach the
previous monitor's profile from the stale name.
- The per-output temperature slider sets `wheelEnabled: false` like the other
drag-finished sliders: `DankSlider`'s wheel handler assigns `value` and emits
`sliderValueChanged` without `sliderDragFinished`, so scrolling dropped the
change, froze the label on the scrolled value and destroyed the value binding.
Covered by TestParseBytesTagTableBounds (allocates 4,299,161,600 bytes at
parser.go:138 and dies with an unrecovered fatal error on the previous
commit), TestManager_ICCStatusServesPublishedSnapshot,
TestManager_RemoveOutputByRegistryNamePrunesNames and
TestManager_ICCStatusConcurrentPublishAndRead; a temporary copy of the getter
test against the previous commit reports DATA RACE and passes here.
* fix(icc): keep the attached profile when a gamma control is re-created
`setupOutputControls` stored a fresh `outputState` for every output it touched,
and `createControls` calls it whenever the controls are rebuilt, so recreating a
control dropped the output's `iccPath`/`iccProfile`/`outputTemp` — configured
state that does not belong to the control. The path is dormant today because
`destroyControls` only runs when nothing is configured (`needsControls()` covers
`ICCProfiles`/`OutputTemps`), but the snapshot published after `createControls`
would then report whatever the rebuilt state holds instead of the profile the
display is configured with.
`controlStateFor` reuses the state of a known output and resets only what belongs
to the new control: the ramp bookkeeping and the failure budget (rampSize,
failed, retryCount, lastFailTime, lastTemp, lastGamma, lastContrast). A control
that has not reported gamma_size yet has to receive its ramp again, while the
profile and the per-output temperature survive. An output seen for the first
time still starts from a clean state.
Covered by TestManager_ControlStateReuseKeepsAttachedICC.
* fix(icc): keep the config a real snapshot and make the per-output temperature apply
Third review round.
- `Config` is copied by value all over the manager, but `ICCProfiles` and
`OutputTemps` are maps, so every copy aliased the ones the manager writes under
`configMutex`. `updateStateFromSchedule` stored such a copy in `m.state` and it
was marshalled on the connection writer goroutine while `ApplyICC` stored a
profile from the IPC goroutine (`fatal error: concurrent map iteration and map
write`, which no `recover()` catches); `SaveConfig` marshalled its copy after
the unlock, and `loadConfiguredICC`/`attachConfiguredICC` indexed the maps after
releasing the lock. Every copy that outlives the lock is cloned now
(`cloneConfig`/`configSnapshot`), so a value copy is a snapshot again.
- `SetOutputTemp` never created the gamma controls. On a default install (night
light off, gamma 1.0, contrast 1.0, no profile, no override) they do not exist,
so the `Range` over `m.outputs` matched nothing: the value was written to
`wayland.json`, no ramp was applied, and the settings slider snapped back to
"Default" until a daemon restart. It now persists first, creates the controls
through `ensureOutputControls` (shared with `ApplyICC`), and pushes the state
from the actor, and the published temperatures report the configured value even
before an output is known.
- A TRC is not a video card gamma ramp: `rTRC`/`gTRC`/`bTRC` describe the
display's own transfer function, so a gamma-2.2 profile was written as
`t^(1/2.2)` — mid gray 0.5 became 47909/65535 — washing the display out instead
of correcting it. `ApplyICC` refuses a profile without `vcgt`, the attach path
skips one with a warning, and `GenerateGammaRamp` returns an error instead of
falling back to the TRC or to an identity ramp. TRC stays profile metadata
(`dms icc info`, the settings dialog).
- `icc: applied ICC ramp` was logged at Info on every 25 K animation step; it is
Debug now, which is where a per-step message belongs.
- `I18n.tr("No information available")` in the profile info modal passes its
translator context, like every other string this PR adds.
Covered by TestManager_ConfigSnapshotOwnsItsMaps,
TestManager_ConfigSnapshotConcurrentMarshal (the previous commit dies with
`fatal error: concurrent map iteration and map write`),
TestManager_SetOutputTempWithoutControlsPublishesValue (the previous commit
reports 0 for the value it just stored), TestGenerateGammaRampRequiresVCGT, and
the updated TestProfileRampWithTemp, whose fixture now carries an identity vcgt
table instead of relying on an empty profile.
* fix(icc): push the state when only the ICC part changed
Found while sweeping the same class of problem: `stateChanged` compared only the
schedule fields, so a change that touches nothing else — applying or removing a
profile, `dms icc set-temp` — was treated as "no change" and the notifier never
pushed it. The settings page then only caught up because the UI path calls
`requestStatus()` afterwards, and the CLI path did not catch up at all, which is
the symptom the omitempty fix was meant to remove.
`iccStateChanged` compares the ICC profile status and the per-output
temperatures, so those changes reach the subscribers on their own. Covered by
the new TestStateChanged cases (profile applied, profile removed, profile
description changed, output temp changed, unchanged ICC state); the four
change cases report `stateChanged() = false` on the previous commit.
* fix(icc): keep the night light state, prune names without a control, use a 0 sentinel
Fifth review round.
- `SaveICCConfig` replaces `SaveConfig` on the three ICC paths (apply, remove,
set-temp). Writing the daemon's whole config persisted the night light fields
it happens to hold in memory: with the night light on, applying a profile
stored `"Enabled": true`, and since the shell only ever sends
`wayland.gamma.setEnabled` when the mode is on, turning it off afterwards (an
in-memory change on the daemon side, no write) left that `true` on disk — after
log out/in the daemon came up driving the schedule while the UI showed night
mode off, with no way to resync short of a toggle. The ICC save now reads the
file and rewrites only `iccProfiles`/`outputTemps`, so the fields the shell
owns stay as they are.
- `removeOutputByRegistryName` resolved the output from `m.outputs`, which only
has entries once the gamma controls exist. On a default install (night light
off, no profile, no override) no control is ever created, so a disconnected
monitor kept its `outputNames`/`outputRegNames` entries for the life of the
daemon: `dms icc status`/`listOutputs` listed monitors that were gone, and both
maps grew with every dock/undock cycle. The object ID is resolved from
`m.outputRegNames` (populated for every `wl_output`), the name entries are
dropped before the output state is looked up, and a state that is known without
a registry name still falls back to matching its own.
- The Display Config temperature row used `7000` as its fallback for an output
with no override. `publishICCState` only copies entries with `temp != 0`, so
the value is absent rather than `0` for an unconfigured output: the card claimed
"7000K" while the daemon drove the night light or neutral, and a user who
deliberately set 7000K got the "no override" colouring because the highlight
tested `!== 7000`. The sentinel is `0` now, which is what the `Default` label
branches and the "is overridden" tests were written against.
Covered by TestSaveICCConfigKeepsNightLightFields (the previous commit brings the
night light back on after a restart), TestManager_RemoveOutputByRegistryNameWithoutControl
(the previous commit keeps an unplugged monitor listed) and the existing
TestManager_RemoveOutputByRegistryNamePrunesNames.
* fix(icc): validate the CLI arguments and the IPC parameters of the ICC commands
Sweep of the two surfaces the review has not looked at yet, so the failures are
found here instead of in the next round.
- `dms icc apply` copied the profile into the config directory before asking the
daemon, and only the *parse* was checked locally. A profile the daemon refuses
(no `vcgt` table, non-RGB color space) was therefore left in the profile
directory for `dms icc list` to keep offering, and an IPC failure left the copy
behind as well. The command now checks the same rules the daemon enforces
before copying anything, and removes the copy it just made when the request
fails (a file that was already there is left alone).
- `dms icc list` marks a profile without a `vcgt` table, so the rule that makes
`apply` refuse it is visible where the profiles are listed.
- `ApplyICC`/`RemoveICC`/`SetOutputTemp` reach the manager over IPC with whatever
the caller sent: an empty (or whitespace-padded) output name used to be
persisted as an entry in `wayland.json` that no `wl_output` can ever match, and
a relative profile path was stored to be resolved again on the next start, from
a different working directory. Both are rejected now, before anything is
written.
Verified with the built CLI against the previous binary: with a profile that has
no vcgt table, `dms icc apply` now exits before touching the config directory
(`residual=[]`) where the previous one copied the file and went on to the IPC
(`residual=[nogamma.icc]`); with a valid profile and no daemon reachable, the
previous one leaves `vcgt.icc` behind and this one does not. Covered by
TestManager_RejectsInvalidICCArguments.
* fix(icc): apply the user gamma and contrast on profiled outputs
* fix(icc): recreate failed controls without the night light and allow clearing a per-output temp
* test(icc): cover the recreated control and the cleared temperature override
Follow-up on d55d3d1f, which fixed both points without tests:
- TestManager_RecreateOutputControlFollowsNeedsControls pins the predicate: with
the night light off and nothing configured there is nothing to recreate, and
with a configured profile or a per-output temperature the control has to be
recreated. Both configured cases return nil on 9226251c.
- TestManager_SetOutputTempZeroClearsTheOverride pins what the reset button in
Display Config does end to end: the stored value and the published entry both
disappear, so the row reads "Default" and the output follows the schedule.
Also keeps the reset button's slot instead of revealing it on demand. The
temperature row shares its column with the slider below it, so the height change
between "Default" (no button) and an override moved the slider 14 px under the
pointer while it was being dragged; the button is now always laid out and only
its opacity and enabled state follow the override, which also lets the label
width drop the conditional.
* fix(icc): replicate a one-channel vcgt and keep the temp slider in sync
* fix(icc): release idle gamma controls and push the output list
* fix(icc): dedupe ramps on the effective target
* fix(icc): never overwrite a same-named profile in the config dir
---------
Co-authored-by: bbedward <[email protected]>
* fix(clipboard): preserve pinned state when editing entries
* fix(clipboard): address PR review feedback on editEntry
* fix(clipboard): validate empty text and entry size in EditEntry
* fix(clipboard): gate saving entry on full text load completion
* fix(clipboard): add user feedback and error fallback for entry loading
* fix(clipboard): keep entry and gate save with error toast on load failure
* fix(clipboard): reject non-text edits and add translator contexts
* fix(clipboard): support alt text mime types in EditEntry and UI guards
* fix(clipboard): pre-fetch entry before opening editor and allow retry on load failure
Adds Fortinet gateway support to the NetworkManager openconnect path.
A SAML gateway authenticates through the browser, with the loopback
redirect handled in core and the session traded for the cookie
openconnect needs. Certificate trust is confirmed once and stored as
the digest openfortivpn uses.
openfortivpn config files can be imported as profiles. A saml-login
line selects the browser login, anything else imports as a password
profile carrying whatever credentials the file had.
Co-authored-by: Claude Opus 5 <[email protected]>
* 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.
- New Entries captured from a mixed image+text offer keep the image as the primary mime i.e. bitmap
- Copy Text context-menu item on atlernates
Closes#2849
* fix(theme): take sun times from the local calendar day, not the UTC one
CalculateSunTimesWithTwilight read its reference day off date.UTC(). The
event seconds it computes are local mean solar time and lonOffset converts
them to UTC, so the instant of a local day's sunrise lands on the previous
UTC day east of Greenwich and a local sunset on the next one west of it.
Whenever the local and UTC calendars disagree, the function therefore
returned a neighbouring day's times.
Everything around it already works in local calendar days: the polar
branches of CalculateSunTimes build their day from date.Year/Month/Day,
thememode's startOfNextDay uses next.Location(), and the gamma scheduler
keys its calcDay cache on now.Location(). Only the reference day inside
the calculation disagreed.
Effect at UTC+8 (Kunming, 25.04N 102.72E): between local sunrise and 08:00
local, computeLocationSchedule got yesterday's sunrise and sunset, both
already past, fell through to the next-day branch and got today's sunrise,
also past. It reported dark with nextTransition in the past, which
schedulerLoop clamps to a one-second wait, so it re-evaluated every second
until 08:00 local and then flipped to light on its own. West of UTC the
mirror image: at UTC-7 the mode went dark from 17:00 local, when the UTC
date rolls over, until the real sunset.
The same SunTimes drive the gamma/night-light scheduler, so night light
shifted by a day the same way.
Fix: derive the reference day from date's own calendar day, keeping
dayStart anchored at UTC midnight so the lonOffset arithmetic is
unchanged, and take the orbit angle from the same day. Callers whose date
is already in UTC are unaffected.
Tests: suncalc_refday_test.go covers the reference day east and west of
UTC, stability across UTC midnight, and that UTC callers do not move.
manager_location_test.go is new to the thememode package and covers
computeLocationSchedule at both offsets, including that nextTransition is
never in the past.
* fix(theme): pick the reference day from the solar day, not the civil one
Taking the reference day straight off the caller's calendar day is right
for nearly every zone, but not for one shifted a full day away from its
own meridian. Apia, Kiritimati, Tongatapu and the Chathams all sit on
west longitudes while keeping a UTC+12:45..+14 offset, so their mean
solar time and their civil time are a day apart. Every sun event landed
on the following local day there, and the location schedule reported
dark around the clock.
Anchor on the caller's local noon and convert that to mean solar time to
pick the reference day. For every other zone this resolves to the same
date as before, so Kunming, Los Angeles and London are unchanged to the
second. dateOrbitAngle now takes the same reference day, so declination
and the equation of time no longer belong to a different day than the
events computed from them.
Covered at both levels: three antimeridian zones in the suncalc test,
and two cases in the location schedule test for the symptom itself.
Both fail without this change.
* feat(clipboard): clear only the filtered entries
With a search query or type filter active, the clear button deleted
every unpinned entry regardless of what the list was showing, so
pruning a subset meant deleting entries one by one from the context
menu.
When the recents list is filtered, the button now clears exactly the
entries it shows and the modal stays open on that filter; with no
filter the previous behaviour is untouched. A filter that matches
nothing does nothing at all, rather than falling back to clearing
everything. The tooltip says "Clear Filtered" while a filter is
active, and the confirmation names the count.
Deleting one id at a time would have cost a round trip and a full
state broadcast per entry, so this adds clipboard.deleteEntries: one
bolt transaction, one state update, and it skips pinned entries
server-side so a bulk delete can never take out saved items.
Fixes#3198
* fix(clipboard): add translator context and list deleteEntries in IPC help
Review follow-up.
The two strings this branch adds carried no translator context: the
"Clear Filtered" tooltip in ClipboardHeader and the confirmation body for
a filtered clear in ClipboardHistoryContent. Both now say where they
appear, and the second one names what %1 is, per CONTRIBUTING.
"Clear All" on the same line is deliberately left alone. It is an
existing shared term with four other call sites, so a context there would
attach a clipboard-specific comment to a term the printer tab also uses.
clipboard.deleteEntries was handled but absent from the IPC method
listing that `dms debug-srv` prints, which left it undiscoverable right
next to clipboard.deleteEntry.
Catalogs untouched.
* chore: re-trigger CI
The lint-and-test failure on 21cefbf is an unrelated flake:
TestStoreEntry_CorruptDBReturnsErrorNotPanic died with SIGBUS in the
bbolt mmap. That test comes from master (c68b7e5) and passes there;
this branch only adds TestDeleteEntries_*/TestHandleDeleteEntries_*
and touches manager.go additively.
* clipboard: survive mmap faults from corrupted db pages
---------
Co-authored-by: bbedward <[email protected]>
* feat: add cellular support
* fix(settings): resolve cellular tab index collision
* fix: address review feedback for cellular support
Bump the network API version, drop the deleted term freeze file,
regenerate the settings search index, and reuse existing translation
terms where they already cover the new cellular UI.
* fix: do not assign readonly userPreference when switching network type
Assigning SettingsData.networkPreference through the readonly alias
threw on click, so the Cellular segment in Control Center did nothing.
* fix: make Cellular selectable and the modem row clickable
The Control Center type switcher was bound only to preference, so
Cellular snapped back to Ethernet. The settings modem row highlighted
on hover but had no click handler. Show the modem as a connect target
when no APN profiles exist.
* fix: create a GSM profile when connecting cellular with none saved
Clicking Mobile broadband only activated an existing profile, so a
modem with no APN did nothing useful. Fall back to AddAndActivate
like ethernet connect.
* fix: address second round of cellular review feedback
- Guard cellularDevices map with devMutex via snapshot/by-iface/set/remove
helpers, mirroring the existing ethernet and wifi accessors
- Regenerate mocks with mockery v3 instead of hand-editing mock_Backend.go
- Reuse refreshCellularState() in SetCellularEnabled, DisconnectCellular,
DisconnectCellularDevice, ActivateCellularConnection and device removal
- Wrap retryErr rather than the first error when the auto-config retry fails
- Use Theme.surfaceTextSecondary/primaryHover/primaryHoverLight in the
cellular-off state instead of hand-rolled Qt.rgba values
- Drop the duplicate "No devices found" label so it can no longer render
twice with no modem and no saved config
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
* fix: address remaining cellular review comments
- Toast "Failed to toggle cellular" instead of always "enable"
- Remove unused enableCellularRadio() wrappers
- Store Control Center network type as a value, not a list index
* fix: pass nmcli connection selector as separate argument
`nmcli con mod uuid:<UUID>` is not valid syntax -- nmcli expects the
selector keyword as its own argument, so every priority update failed
with "no such connection profile". Because practically every NM profile
has a UUID, this silently disabled autoconnect-priority and route-metric
updates for ethernet and WiFi as well as cellular.
Also fix the Cellular settings status text, which said "Connecting..."
for a flag that only tracks radio enable/disable, and add the seven
cellular terms that were missing from the translation catalogs.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
* apply review comments
* fix lints
* update debug doc
* fix style inconsistencies
---------
Co-authored-by: Yechiel Worenklein <[email protected]>
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
Co-authored-by: bbedward <[email protected]>
* feat(theme): add support for matugen smart mode and type
* add another dry run to get smart type preview
* fix too much keywords in search index
* revert dont extract translations
* feat gate "Auto From Wallpaper" toggle row and the available matugen scheme for the pallete drop down
* re-extract settings search index
* make portal sync no longer disables matugen smart mode
* make sure cosmic theme mode also follow change from smart mode
* add translator context for Auto (Light Mode) / Auto (Dark Mode) / Auto From Wallpaper
* fix: gate matugen smart mode checks on the dynamic theme so stock themes keep portal sync and fix tile labels in control center
* fix(suncalc): parenthesise the sunrise-equation denominator
`sunHourAngle` computed
cos(z) / cos(lat) * cos(dec) - tan(lat) * tan(dec)
but the sunrise equation is
cos(H) = cos(z) / (cos(lat) * cos(dec)) - tan(lat) * tan(dec)
In Go `a / b * c` is `(a / b) * c`, so `cos(dec)` multiplied where it should divide.
The new test asserts a property rather than a formula: feeding the returned hour
angle back through the definition of the zenith angle,
cos(z) = sin(lat)*sin(dec) + cos(lat)*cos(dec)*cos(H)
has to reproduce the zenith angle that was requested. It fails on the old expression
and passes on the corrected one, over a grid of latitudes from the equator to the
polar circle, declinations across a full year, and both zenith targets the callers
use (elevTwilight -6, elevDaylight 3).
Worst-case error before the fix, in clock time:
Singapore lat 1.35 285 s
Mexico City lat 19.43 312 s
Cairo lat 30.04 354 s
New York lat 40.71 439 s
Trieste lat 45.69 512 s
London lat 51.51 671 s
Oslo lat 59.91 654 s
Tromso lat 69.65 1443 s
The error grows with latitude and with |declination|, and is largest at the civil
twilight zenith — which is where the gamma ramp starts and ends.
It also moves the boundary at which Acos leaves its domain, i.e. where the code
decides midnight sun / polar night. Swept over 505062 (lat, dec, zenith) points, the
classification differs at 961 of them (0.190%), all beyond 88 degrees of latitude.
The existing suncalc tests keep passing: they assert sunrise and sunset to the hour,
which is two orders of magnitude coarser than this error.
* fix(suncalc): classify each solar threshold independently
---------
Co-authored-by: Mark2Mac <[email protected]>
Co-authored-by: bbedward <[email protected]>