AvengeMedia / AvengeMedia/DankMaterialShell
Night mode: software overlay fallback when hardware gamma is unavailable (Apple Silicon/Asahi)
- Dominant language
- QML
- Stars
- 8.1k
- Forks
- 515
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 102
Description
## Problem
On Apple Silicon (Asahi Linux), DMS night mode reports as enabled but has no visible effect. The DMS backend initializes gamma control successfully via `zwlr_gamma_control_v1`, but the compositor (niri) cannot apply the gamma LUT because the Apple DCP kernel driver does not expose the `GAMMA_LUT` CRTC property.
This affects all Apple Silicon Macs running Asahi Linux with niri (and likely sway/Hyprland too).
The `gammaControlAvailable` property in `DisplayService` reports `true` because the Wayland protocol initializes without error — but the actual display color never changes.
## Root cause
- Apple DCP DRM driver: `gamma_size=0`, no `GAMMA_LUT` property
- Niri accepts `zwlr_gamma_control_v1` requests but silently no-ops since there's no LUT to set
- DMS backend sees success, `DisplayService.gammaControlAvailable = true`
- Upstream tracker: [AsahiLinux/linux#91](https://github.com/AsahiLinux/linux/issues/91)
- Niri CTM fallback request: [niri-wm/niri#3672](https://github.com/niri-wm/niri/issues/3672)
## Workaround (working DMS plugin)
I wrote a daemon plugin that creates a click-through layer-shell overlay with a warm color tint when night mode is enabled. It works well as an immediate workaround:
```qml
// ~/.config/DankMaterialShell/plugins/nightOverlay/NightOverlay.qml
import QtQuick
import Quickshell
import Quickshell.Wayland
import qs.Common
import qs.Services
Item {
id: root
property var pluginService: null
property string pluginId: ""
readonly property bool shouldShow: SessionData.nightModeEnabled
function tempToColor(kelvin) {
if (kelvin >= 6000) return Qt.rgba(1, 0.82, 0.48, 0.04);
if (kelvin >= 5000) return Qt.rgba(1, 0.68, 0.28, 0.09);
if (kelvin >= 4000) return Qt.rgba(1, 0.56, 0.18, 0.14);
if (kelvin >= 3500) return Qt.rgba(1, 0.46, 0.10, 0.18);
if (kelvin >= 3000) return Qt.rgba(1, 0.38, 0.06, 0.22);
return Qt.rgba(1, 0.32, 0.03, 0.26);
}
readonly property color tintColor: tempToColor(SessionData.nightModeTemperature)
Variants {
model: root.shouldShow ? Quickshell.screens : []
PanelWindow {
required property var modelData
screen: modelData
anchors { left: true; right: true; top: true; bottom: true }
mask: Region {}
WlrLayershell.namespace: "dms:night-overlay"
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.exclusionMode: ExclusionMode.Ignore
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
color: "transparent"
Rectangle {
anchors.fill: parent
color: root.tintColor
Behavior on color { ColorAnimation { duration: 500 } }
}
}
}
}
```
## Feature request
Consider adding a built-in software fallback to DMS's gamma control system:
1. **Detect gamma failure**: After enabling gamma via the backend, check if `gammaCurrentTemp` actually changes (with a short timeout). If it stays at 0, the hardware path is broken.
2. **Overlay fallback**: Create a click-through layer-shell overlay (exactly like the plugin above) as a built-in fallback when hardware gamma is unavailable.
3. **UI indicator**: Show a note in Settings > Gamma Control that software mode is active.
This is a better long-term solution than requiring users to install a plugin, since it would work out of the box on affected hardware.
## System info
- DMS 1.4.4
- niri 25.11
- Kernel 6.18.15-400.asahi.fc43.aarch64+16k
- Apple M2 (MacBook Air)
Contributor guide
Research direction
Start by reading the working workaround at ~/.config/DankMaterialShell/plugins/nightOverlay/NightOverlay.qml and tracing the existing DisplayService gamma-control path and Settings > Gamma Control UI. Determine how gammaCurrentTemp is reported after enablement and how layer-shell overlays are created. Done means a built-in software overlay activates when hardware gamma has no effect and the UI identifies software mode.
Written by the indexing model from the issue text.
Assessment
- Domain
- desktop
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100