1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -05:00

gamma: switch to wlsunset-style transitions

This commit is contained in:
bbedward
2025-12-09 09:44:16 -05:00
parent bc27253cbf
commit 5647323449
12 changed files with 854 additions and 964 deletions

View File

@@ -22,6 +22,8 @@ linters:
- (*os.Process).Signal
- (*os.Process).Kill
- syscall.Kill
# Seek on memfd (reset position before passing fd)
- syscall.Seek
# DBus cleanup
- (*github.com/godbus/dbus/v5.Conn).RemoveMatchSignal
- (*github.com/godbus/dbus/v5.Conn).RemoveSignal

View File

@@ -154,11 +154,12 @@ func (n *NiriProvider) convertKeybind(kb *NiriKeyBinding, subcategory string, co
}
bind := keybinds.Keybind{
Key: keyStr,
Description: kb.Description,
Action: rawAction,
Subcategory: subcategory,
Source: source,
Key: keyStr,
Description: kb.Description,
Action: rawAction,
Subcategory: subcategory,
Source: source,
HideOnOverlay: kb.HideOnOverlay,
}
if source == "dms" && conflicts != nil {

View File

@@ -11,12 +11,13 @@ import (
)
type NiriKeyBinding struct {
Mods []string
Key string
Action string
Args []string
Description string
Source string
Mods []string
Key string
Action string
Args []string
Description string
HideOnOverlay bool
Source string
}
type NiriSection struct {
@@ -273,19 +274,26 @@ func (p *NiriParser) parseKeybindNode(node *document.Node, _ string) *NiriKeyBin
}
var description string
var hideOnOverlay bool
if node.Properties != nil {
if val, ok := node.Properties.Get("hotkey-overlay-title"); ok {
description = val.ValueString()
switch val.ValueString() {
case "null", "":
hideOnOverlay = true
default:
description = val.ValueString()
}
}
}
return &NiriKeyBinding{
Mods: mods,
Key: key,
Action: action,
Args: args,
Description: description,
Source: p.currentSource,
Mods: mods,
Key: key,
Action: action,
Args: args,
Description: description,
HideOnOverlay: hideOnOverlay,
Source: p.currentSource,
}
}

View File

@@ -1,12 +1,13 @@
package keybinds
type Keybind struct {
Key string `json:"key"`
Description string `json:"desc"`
Action string `json:"action,omitempty"`
Subcategory string `json:"subcat,omitempty"`
Source string `json:"source,omitempty"`
Conflict *Keybind `json:"conflict,omitempty"`
Key string `json:"key"`
Description string `json:"desc"`
Action string `json:"action,omitempty"`
Subcategory string `json:"subcat,omitempty"`
Source string `json:"source,omitempty"`
HideOnOverlay bool `json:"hideOnOverlay,omitempty"`
Conflict *Keybind `json:"conflict,omitempty"`
}
type DMSBindsStatus struct {

View File

@@ -238,9 +238,17 @@ func (i *ZwlrOutputManagerV1) Dispatch(opcode uint32, fd int, data []byte) {
l := 0
objectID := client.Uint32(data[l : l+4])
proxy := i.Context().GetProxy(objectID)
if proxy != nil {
e.Head = proxy.(*ZwlrOutputHeadV1)
if proxy == nil {
head := &ZwlrOutputHeadV1{}
head.SetContext(i.Context())
head.SetID(objectID)
registerServerProxy(i.Context(), head, objectID)
e.Head = head
} else if head, ok := proxy.(*ZwlrOutputHeadV1); ok {
e.Head = head
} else {
// Stale proxy of wrong type (can happen after suspend/resume)
// Replace it with the correct type
head := &ZwlrOutputHeadV1{}
head.SetContext(i.Context())
head.SetID(objectID)
@@ -715,9 +723,17 @@ func (i *ZwlrOutputHeadV1) Dispatch(opcode uint32, fd int, data []byte) {
l := 0
objectID := client.Uint32(data[l : l+4])
proxy := i.Context().GetProxy(objectID)
if proxy != nil {
e.Mode = proxy.(*ZwlrOutputModeV1)
if proxy == nil {
mode := &ZwlrOutputModeV1{}
mode.SetContext(i.Context())
mode.SetID(objectID)
registerServerProxy(i.Context(), mode, objectID)
e.Mode = mode
} else if mode, ok := proxy.(*ZwlrOutputModeV1); ok {
e.Mode = mode
} else {
// Stale proxy of wrong type (can happen after suspend/resume)
// Replace it with the correct type
mode := &ZwlrOutputModeV1{}
mode.SetContext(i.Context())
mode.SetID(objectID)
@@ -743,7 +759,26 @@ func (i *ZwlrOutputHeadV1) Dispatch(opcode uint32, fd int, data []byte) {
}
var e ZwlrOutputHeadV1CurrentModeEvent
l := 0
e.Mode = i.Context().GetProxy(client.Uint32(data[l : l+4])).(*ZwlrOutputModeV1)
objectID := client.Uint32(data[l : l+4])
proxy := i.Context().GetProxy(objectID)
if proxy == nil {
// Mode not yet registered, create it
mode := &ZwlrOutputModeV1{}
mode.SetContext(i.Context())
mode.SetID(objectID)
registerServerProxy(i.Context(), mode, objectID)
e.Mode = mode
} else if mode, ok := proxy.(*ZwlrOutputModeV1); ok {
e.Mode = mode
} else {
// Stale proxy of wrong type (can happen after suspend/resume)
// Replace it with the correct type
mode := &ZwlrOutputModeV1{}
mode.SetContext(i.Context())
mode.SetID(objectID)
registerServerProxy(i.Context(), mode, objectID)
e.Mode = mode
}
l += 4
i.currentModeHandler(e)

View File

@@ -2,8 +2,6 @@ package wayland
import (
"math"
"github.com/AvengeMedia/DankMaterialShell/core/internal/utils"
)
type GammaRamp struct {
@@ -12,6 +10,126 @@ type GammaRamp struct {
Blue []uint16
}
type rgb struct {
r, g, b float64
}
type xyz struct {
x, y, z float64
}
func illuminantD(temp int) (float64, float64, bool) {
var x float64
switch {
case temp >= 2500 && temp <= 7000:
t := float64(temp)
x = 0.244063 + 0.09911e3/t + 2.9678e6/(t*t) - 4.6070e9/(t*t*t)
case temp > 7000 && temp <= 25000:
t := float64(temp)
x = 0.237040 + 0.24748e3/t + 1.9018e6/(t*t) - 2.0064e9/(t*t*t)
default:
return 0, 0, false
}
y := -3*(x*x) + 2.870*x - 0.275
return x, y, true
}
func planckianLocus(temp int) (float64, float64, bool) {
var x, y float64
switch {
case temp >= 1667 && temp <= 4000:
t := float64(temp)
x = -0.2661239e9/(t*t*t) - 0.2343589e6/(t*t) + 0.8776956e3/t + 0.179910
if temp <= 2222 {
y = -1.1064814*(x*x*x) - 1.34811020*(x*x) + 2.18555832*x - 0.20219683
} else {
y = -0.9549476*(x*x*x) - 1.37418593*(x*x) + 2.09137015*x - 0.16748867
}
case temp > 4000 && temp < 25000:
t := float64(temp)
x = -3.0258469e9/(t*t*t) + 2.1070379e6/(t*t) + 0.2226347e3/t + 0.240390
y = 3.0817580*(x*x*x) - 5.87338670*(x*x) + 3.75112997*x - 0.37001483
default:
return 0, 0, false
}
return x, y, true
}
func srgbGamma(value, gamma float64) float64 {
if value <= 0.0031308 {
return 12.92 * value
}
return math.Pow(1.055*value, 1.0/gamma) - 0.055
}
func clamp01(v float64) float64 {
switch {
case v > 1.0:
return 1.0
case v < 0.0:
return 0.0
default:
return v
}
}
func xyzToSRGB(c xyz) rgb {
return rgb{
r: srgbGamma(clamp01(3.2404542*c.x-1.5371385*c.y-0.4985314*c.z), 2.2),
g: srgbGamma(clamp01(-0.9692660*c.x+1.8760108*c.y+0.0415560*c.z), 2.2),
b: srgbGamma(clamp01(0.0556434*c.x-0.2040259*c.y+1.0572252*c.z), 2.2),
}
}
func normalizeRGB(c *rgb) {
maxw := math.Max(c.r, math.Max(c.g, c.b))
if maxw > 0 {
c.r /= maxw
c.g /= maxw
c.b /= maxw
}
}
func calcWhitepoint(temp int) rgb {
if temp == 6500 {
return rgb{r: 1.0, g: 1.0, b: 1.0}
}
var wp xyz
switch {
case temp >= 25000:
x, y, _ := illuminantD(25000)
wp.x = x
wp.y = y
case temp >= 4000:
x, y, _ := illuminantD(temp)
wp.x = x
wp.y = y
case temp >= 2500:
x1, y1, _ := illuminantD(temp)
x2, y2, _ := planckianLocus(temp)
factor := float64(4000-temp) / 1500.0
sineFactor := (math.Cos(math.Pi*factor) + 1.0) / 2.0
wp.x = x1*sineFactor + x2*(1.0-sineFactor)
wp.y = y1*sineFactor + y2*(1.0-sineFactor)
default:
t := temp
if t < 1667 {
t = 1667
}
x, y, _ := planckianLocus(t)
wp.x = x
wp.y = y
}
wp.z = 1.0 - wp.x - wp.y
wpRGB := xyzToSRGB(wp)
normalizeRGB(&wpRGB)
return wpRGB
}
func GenerateGammaRamp(size uint32, temp int, gamma float64) GammaRamp {
ramp := GammaRamp{
Red: make([]uint16, size),
@@ -19,16 +137,13 @@ func GenerateGammaRamp(size uint32, temp int, gamma float64) GammaRamp {
Blue: make([]uint16, size),
}
wp := calcWhitepoint(temp)
for i := uint32(0); i < size; i++ {
val := float64(i) / float64(size-1)
valGamma := math.Pow(val, 1.0/gamma)
r, g, b := temperatureToRGB(temp)
ramp.Red[i] = uint16(utils.Clamp(valGamma*r*65535.0, 0, 65535))
ramp.Green[i] = uint16(utils.Clamp(valGamma*g*65535.0, 0, 65535))
ramp.Blue[i] = uint16(utils.Clamp(valGamma*b*65535.0, 0, 65535))
ramp.Red[i] = uint16(clamp01(math.Pow(val*wp.r, 1.0/gamma)) * 65535.0)
ramp.Green[i] = uint16(clamp01(math.Pow(val*wp.g, 1.0/gamma)) * 65535.0)
ramp.Blue[i] = uint16(clamp01(math.Pow(val*wp.b, 1.0/gamma)) * 65535.0)
}
return ramp
@@ -50,39 +165,3 @@ func GenerateIdentityRamp(size uint32) GammaRamp {
return ramp
}
func temperatureToRGB(temp int) (float64, float64, float64) {
tempK := float64(temp) / 100.0
var r, g, b float64
if tempK <= 66 {
r = 1.0
} else {
r = tempK - 60
r = 329.698727446 * math.Pow(r, -0.1332047592)
r = utils.Clamp(r, 0, 255) / 255.0
}
if tempK <= 66 {
g = tempK
g = 99.4708025861*math.Log(g) - 161.1195681661
g = utils.Clamp(g, 0, 255) / 255.0
} else {
g = tempK - 60
g = 288.1221695283 * math.Pow(g, -0.0755148492)
g = utils.Clamp(g, 0, 255) / 255.0
}
if tempK >= 66 {
b = 1.0
} else if tempK <= 19 {
b = 0.0
} else {
b = tempK - 10
b = 138.5177312231*math.Log(b) - 305.0447927307
b = utils.Clamp(b, 0, 255) / 255.0
}
return r, g, b
}

View File

@@ -54,7 +54,7 @@ func TestGenerateGammaRamp(t *testing.T) {
}
}
func TestTemperatureToRGB(t *testing.T) {
func TestCalcWhitepoint(t *testing.T) {
tests := []struct {
name string
temp int
@@ -67,32 +67,32 @@ func TestTemperatureToRGB(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r, g, b := temperatureToRGB(tt.temp)
wp := calcWhitepoint(tt.temp)
if r < 0 || r > 1 {
t.Errorf("red out of range: %f", r)
if wp.r < 0 || wp.r > 1 {
t.Errorf("red out of range: %f", wp.r)
}
if g < 0 || g > 1 {
t.Errorf("green out of range: %f", g)
if wp.g < 0 || wp.g > 1 {
t.Errorf("green out of range: %f", wp.g)
}
if b < 0 || b > 1 {
t.Errorf("blue out of range: %f", b)
if wp.b < 0 || wp.b > 1 {
t.Errorf("blue out of range: %f", wp.b)
}
})
}
}
func TestTemperatureProgression(t *testing.T) {
func TestWhitepointProgression(t *testing.T) {
temps := []int{3000, 4000, 5000, 6000, 6500}
var prevBlue float64
for i, temp := range temps {
_, _, b := temperatureToRGB(temp)
if i > 0 && b < prevBlue {
wp := calcWhitepoint(temp)
if i > 0 && wp.b < prevBlue {
t.Errorf("blue should increase with temperature, %d->%d: %f->%f",
temps[i-1], temp, prevBlue, b)
temps[i-1], temp, prevBlue, wp.b)
}
prevBlue = b
prevBlue = wp.b
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,81 +6,117 @@ import (
)
const (
degToRad = math.Pi / 180.0
radToDeg = 180.0 / math.Pi
solarNoon = 12.0
sunriseAngle = -0.833
degToRad = math.Pi / 180.0
radToDeg = 180.0 / math.Pi
)
func CalculateSunTimes(lat, lon float64, date time.Time) SunTimes {
utcDate := date.UTC()
year, month, day := utcDate.Date()
loc := date.Location()
type SunCondition int
dayOfYear := utcDate.YearDay()
const (
SunNormal SunCondition = iota
SunMidnightSun
SunPolarNight
)
gamma := 2 * math.Pi / 365 * float64(dayOfYear-1)
type SunTimes struct {
Dawn time.Time
Sunrise time.Time
Sunset time.Time
Night time.Time
}
eqTime := 229.18 * (0.000075 +
0.001868*math.Cos(gamma) -
0.032077*math.Sin(gamma) -
0.014615*math.Cos(2*gamma) -
0.040849*math.Sin(2*gamma))
func daysInYear(year int) int {
if (year%4 == 0 && year%100 != 0) || year%400 == 0 {
return 366
}
return 365
}
decl := 0.006918 -
0.399912*math.Cos(gamma) +
0.070257*math.Sin(gamma) -
0.006758*math.Cos(2*gamma) +
0.000907*math.Sin(2*gamma) -
0.002697*math.Cos(3*gamma) +
0.00148*math.Sin(3*gamma)
func dateOrbitAngle(t time.Time) float64 {
return 2 * math.Pi / float64(daysInYear(t.Year())) * float64(t.YearDay()-1)
}
func equationOfTime(orbitAngle float64) float64 {
return 4 * (0.000075 +
0.001868*math.Cos(orbitAngle) -
0.032077*math.Sin(orbitAngle) -
0.014615*math.Cos(2*orbitAngle) -
0.040849*math.Sin(2*orbitAngle))
}
func sunDeclination(orbitAngle float64) float64 {
return 0.006918 -
0.399912*math.Cos(orbitAngle) +
0.070257*math.Sin(orbitAngle) -
0.006758*math.Cos(2*orbitAngle) +
0.000907*math.Sin(2*orbitAngle) -
0.002697*math.Cos(3*orbitAngle) +
0.00148*math.Sin(3*orbitAngle)
}
func sunHourAngle(latRad, declination, targetSunRad float64) float64 {
return math.Acos(math.Cos(targetSunRad)/
math.Cos(latRad)*math.Cos(declination) -
math.Tan(latRad)*math.Tan(declination))
}
func hourAngleToSeconds(hourAngle, eqtime float64) float64 {
return radToDeg * (4.0*math.Pi - 4*hourAngle - eqtime) * 60
}
func sunCondition(latRad, declination float64) SunCondition {
signLat := latRad >= 0
signDecl := declination >= 0
if signLat == signDecl {
return SunMidnightSun
}
return SunPolarNight
}
func CalculateSunTimesWithTwilight(lat, lon float64, date time.Time, elevTwilight, elevDaylight float64) (SunTimes, SunCondition) {
latRad := lat * degToRad
elevTwilightRad := (90.833 - elevTwilight) * degToRad
elevDaylightRad := (90.833 - elevDaylight) * degToRad
cosHourAngle := (math.Sin(sunriseAngle*degToRad) -
math.Sin(latRad)*math.Sin(decl)) /
(math.Cos(latRad) * math.Cos(decl))
utc := date.UTC()
orbitAngle := dateOrbitAngle(utc)
decl := sunDeclination(orbitAngle)
eqtime := equationOfTime(orbitAngle)
if cosHourAngle > 1 {
return SunTimes{
Sunrise: time.Date(year, month, day, 0, 0, 0, 0, time.UTC).In(loc),
Sunset: time.Date(year, month, day, 0, 0, 0, 0, time.UTC).In(loc),
}
}
if cosHourAngle < -1 {
return SunTimes{
Sunrise: time.Date(year, month, day, 0, 0, 0, 0, time.UTC).In(loc),
Sunset: time.Date(year, month, day, 23, 59, 59, 0, time.UTC).In(loc),
}
haTwilight := sunHourAngle(latRad, decl, elevTwilightRad)
haDaylight := sunHourAngle(latRad, decl, elevDaylightRad)
if math.IsNaN(haTwilight) || math.IsNaN(haDaylight) {
cond := sunCondition(latRad, decl)
return SunTimes{}, cond
}
hourAngle := math.Acos(cosHourAngle) * radToDeg
dayStart := time.Date(utc.Year(), utc.Month(), utc.Day(), 0, 0, 0, 0, time.UTC)
lonOffset := time.Duration(-lon*4) * time.Minute
sunriseTime := solarNoon - hourAngle/15.0 - lon/15.0 - eqTime/60.0
sunsetTime := solarNoon + hourAngle/15.0 - lon/15.0 - eqTime/60.0
sunrise := timeOfDayToTime(sunriseTime, year, month, day, time.UTC).In(loc)
sunset := timeOfDayToTime(sunsetTime, year, month, day, time.UTC).In(loc)
dawnSecs := hourAngleToSeconds(math.Abs(haTwilight), eqtime)
sunriseSecs := hourAngleToSeconds(math.Abs(haDaylight), eqtime)
sunsetSecs := hourAngleToSeconds(-math.Abs(haDaylight), eqtime)
nightSecs := hourAngleToSeconds(-math.Abs(haTwilight), eqtime)
return SunTimes{
Sunrise: sunrise,
Sunset: sunset,
}
Dawn: dayStart.Add(time.Duration(dawnSecs)*time.Second + lonOffset).In(date.Location()),
Sunrise: dayStart.Add(time.Duration(sunriseSecs)*time.Second + lonOffset).In(date.Location()),
Sunset: dayStart.Add(time.Duration(sunsetSecs)*time.Second + lonOffset).In(date.Location()),
Night: dayStart.Add(time.Duration(nightSecs)*time.Second + lonOffset).In(date.Location()),
}, SunNormal
}
func timeOfDayToTime(hours float64, year int, month time.Month, day int, loc *time.Location) time.Time {
h := int(hours)
m := int((hours - float64(h)) * 60)
s := int(((hours-float64(h))*60 - float64(m)) * 60)
if h < 0 {
h += 24
day--
func CalculateSunTimes(lat, lon float64, date time.Time) SunTimes {
times, cond := CalculateSunTimesWithTwilight(lat, lon, date, -6.0, 3.0)
switch cond {
case SunMidnightSun:
dayStart := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location())
dayEnd := dayStart.Add(24*time.Hour - time.Second)
return SunTimes{Dawn: dayStart, Sunrise: dayStart, Sunset: dayEnd, Night: dayEnd}
case SunPolarNight:
dayStart := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location())
return SunTimes{Dawn: dayStart, Sunrise: dayStart, Sunset: dayStart, Night: dayStart}
}
if h >= 24 {
h -= 24
day++
}
return time.Date(year, month, day, h, m, s, 0, loc)
return times
}

View File

@@ -340,38 +340,47 @@ func TestCalculateNextTransition(t *testing.T) {
}
}
func TestTimeOfDayToTime(t *testing.T) {
func TestSunTimesWithTwilight(t *testing.T) {
lat := 40.7128
lon := -74.0060
date := time.Date(2024, 6, 21, 12, 0, 0, 0, time.Local)
times, cond := CalculateSunTimesWithTwilight(lat, lon, date, -6.0, 3.0)
if cond != SunNormal {
t.Errorf("expected SunNormal, got %v", cond)
}
if !times.Dawn.Before(times.Sunrise) {
t.Error("dawn should be before sunrise")
}
if !times.Sunrise.Before(times.Sunset) {
t.Error("sunrise should be before sunset")
}
if !times.Sunset.Before(times.Night) {
t.Error("sunset should be before night")
}
}
func TestSunConditions(t *testing.T) {
tests := []struct {
name string
hours float64
expected time.Time
lat float64
date time.Time
expected SunCondition
}{
{
name: "noon",
hours: 12.0,
expected: time.Date(2024, 6, 21, 12, 0, 0, 0, time.Local),
},
{
name: "half_past",
hours: 12.5,
expected: time.Date(2024, 6, 21, 12, 30, 0, 0, time.Local),
},
{
name: "early_morning",
hours: 6.25,
expected: time.Date(2024, 6, 21, 6, 15, 0, 0, time.Local),
name: "normal_conditions",
lat: 40.0,
date: time.Date(2024, 6, 21, 12, 0, 0, 0, time.UTC),
expected: SunNormal,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := timeOfDayToTime(tt.hours, 2024, 6, 21, time.Local)
if result.Hour() != tt.expected.Hour() {
t.Errorf("hour = %d, want %d", result.Hour(), tt.expected.Hour())
}
if result.Minute() != tt.expected.Minute() {
t.Errorf("minute = %d, want %d", result.Minute(), tt.expected.Minute())
_, cond := CalculateSunTimesWithTwilight(tt.lat, 0, tt.date, -6.0, 3.0)
if cond != tt.expected {
t.Errorf("expected condition %v, got %v", tt.expected, cond)
}
})
}

View File

@@ -11,18 +11,28 @@ import (
"github.com/godbus/dbus/v5"
)
type GammaState int
const (
StateNormal GammaState = iota
StateTransition
StateStatic
)
type Config struct {
Outputs []string
LowTemp int
HighTemp int
Latitude *float64
Longitude *float64
UseIPLocation bool
ManualSunrise *time.Time
ManualSunset *time.Time
ManualDuration *time.Duration
Gamma float64
Enabled bool
Outputs []string
LowTemp int
HighTemp int
Latitude *float64
Longitude *float64
UseIPLocation bool
ManualSunrise *time.Time
ManualSunset *time.Time
ManualDuration *time.Duration
Gamma float64
Enabled bool
ElevationTwilight float64
ElevationDaylight float64
}
type State struct {
@@ -31,13 +41,24 @@ type State struct {
NextTransition time.Time `json:"nextTransition"`
SunriseTime time.Time `json:"sunriseTime"`
SunsetTime time.Time `json:"sunsetTime"`
DawnTime time.Time `json:"dawnTime"`
NightTime time.Time `json:"nightTime"`
IsDay bool `json:"isDay"`
SunPosition float64 `json:"sunPosition"`
}
type cmd struct {
fn func()
}
type sunSchedule struct {
times SunTimes
condition SunCondition
dawnStepTime time.Duration
nightStepTime time.Duration
calcDay time.Time
}
type Manager struct {
config Config
configMutex sync.RWMutex
@@ -60,10 +81,9 @@ type Manager struct {
updateTrigger chan struct{}
wg sync.WaitGroup
currentTemp int
targetTemp int
transitionMutex sync.RWMutex
transitionChan chan int
schedule sunSchedule
scheduleMutex sync.RWMutex
gammaState GammaState
cachedIPLat *float64
cachedIPLon *float64
@@ -80,7 +100,6 @@ type Manager struct {
type outputState struct {
id uint32
name string
registryName uint32
output *wlclient.Output
gammaControl any
@@ -91,18 +110,15 @@ type outputState struct {
lastFailTime time.Time
}
type SunTimes struct {
Sunrise time.Time
Sunset time.Time
}
func DefaultConfig() Config {
return Config{
Outputs: []string{},
LowTemp: 4000,
HighTemp: 6500,
Gamma: 1.0,
Enabled: false,
Outputs: []string{},
LowTemp: 4000,
HighTemp: 6500,
Gamma: 1.0,
Enabled: false,
ElevationTwilight: -6.0,
ElevationDaylight: 3.0,
}
}
@@ -140,8 +156,7 @@ func (m *Manager) GetState() State {
if m.state == nil {
return State{}
}
stateCopy := *m.state
return stateCopy
return *m.state
}
func (m *Manager) Subscribe(id string) chan State {
@@ -185,5 +200,8 @@ func stateChanged(old, new *State) bool {
if old.Config.Enabled != new.Config.Enabled {
return true
}
if old.SunPosition != new.SunPosition {
return true
}
return false
}

View File

@@ -96,6 +96,8 @@ DankModal {
for (let i = 0; i < binds.length; i++) {
const bind = binds[i];
if (bind.hideOnOverlay)
continue;
if (bind.subcat) {
hasSubcats = true;
if (!subcats[bind.subcat])
@@ -108,6 +110,9 @@ DankModal {
}
}
if (Object.keys(subcats).length === 0)
continue;
processed[cat] = {
hasSubcats: hasSubcats,
subcats: subcats,