1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00

rename backend to core

This commit is contained in:
bbedward
2025-11-12 23:12:31 -05:00
parent 0fdc0748cf
commit db584b7897
280 changed files with 265 additions and 265 deletions

View File

@@ -0,0 +1,379 @@
package brightness
import (
"fmt"
"sort"
"strings"
"time"
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
)
func NewManager() (*Manager, error) {
return NewManagerWithOptions(false)
}
func NewManagerWithOptions(exponential bool) (*Manager, error) {
m := &Manager{
subscribers: make(map[string]chan State),
updateSubscribers: make(map[string]chan DeviceUpdate),
stopChan: make(chan struct{}),
exponential: exponential,
}
go m.initLogind()
go m.initSysfs()
go m.initDDC()
return m, nil
}
func (m *Manager) initLogind() {
log.Debug("Initializing logind backend...")
logind, err := NewLogindBackend()
if err != nil {
log.Infof("Logind backend not available: %v", err)
log.Info("Will use direct sysfs access for brightness control")
return
}
m.logindBackend = logind
m.logindReady = true
log.Info("Logind backend initialized - will use for brightness control")
}
func (m *Manager) initSysfs() {
log.Debug("Initializing sysfs backend...")
sysfs, err := NewSysfsBackend()
if err != nil {
log.Warnf("Failed to initialize sysfs backend: %v", err)
return
}
devices, err := sysfs.GetDevices()
if err != nil {
log.Warnf("Failed to get initial sysfs devices: %v", err)
m.sysfsBackend = sysfs
m.sysfsReady = true
m.updateState()
return
}
log.Infof("Sysfs backend initialized with %d devices", len(devices))
for _, d := range devices {
log.Debugf(" - %s: %s (%d%%)", d.ID, d.Name, d.CurrentPercent)
}
m.sysfsBackend = sysfs
m.sysfsReady = true
m.updateState()
}
func (m *Manager) initDDC() {
ddc, err := NewDDCBackend()
if err != nil {
log.Debugf("Failed to initialize DDC backend: %v", err)
return
}
m.ddcBackend = ddc
m.ddcReady = true
log.Info("DDC backend initialized")
m.updateState()
}
func (m *Manager) Rescan() {
log.Debug("Rescanning brightness devices...")
m.updateState()
}
func sortDevices(devices []Device) {
sort.Slice(devices, func(i, j int) bool {
classOrder := map[DeviceClass]int{
ClassBacklight: 0,
ClassDDC: 1,
ClassLED: 2,
}
orderI := classOrder[devices[i].Class]
orderJ := classOrder[devices[j].Class]
if orderI != orderJ {
return orderI < orderJ
}
return devices[i].Name < devices[j].Name
})
}
func stateChanged(old, new State) bool {
if len(old.Devices) != len(new.Devices) {
return true
}
oldMap := make(map[string]Device)
for _, d := range old.Devices {
oldMap[d.ID] = d
}
for _, newDev := range new.Devices {
oldDev, exists := oldMap[newDev.ID]
if !exists {
return true
}
if oldDev.Current != newDev.Current || oldDev.Max != newDev.Max {
return true
}
}
return false
}
func (m *Manager) updateState() {
allDevices := make([]Device, 0)
if m.sysfsReady && m.sysfsBackend != nil {
devices, err := m.sysfsBackend.GetDevices()
if err != nil {
log.Debugf("Failed to get sysfs devices: %v", err)
}
if err == nil {
allDevices = append(allDevices, devices...)
}
}
if m.ddcReady && m.ddcBackend != nil {
devices, err := m.ddcBackend.GetDevices()
if err != nil {
log.Debugf("Failed to get DDC devices: %v", err)
}
if err == nil {
allDevices = append(allDevices, devices...)
}
}
sortDevices(allDevices)
m.stateMutex.Lock()
oldState := m.state
newState := State{Devices: allDevices}
if !stateChanged(oldState, newState) {
m.stateMutex.Unlock()
return
}
m.state = newState
m.stateMutex.Unlock()
log.Debugf("State changed, notifying subscribers")
m.NotifySubscribers()
}
func (m *Manager) SetBrightness(deviceID string, percent int) error {
return m.SetBrightnessWithMode(deviceID, percent, m.exponential)
}
func (m *Manager) SetBrightnessWithMode(deviceID string, percent int, exponential bool) error {
return m.SetBrightnessWithExponent(deviceID, percent, exponential, 1.2)
}
func (m *Manager) SetBrightnessWithExponent(deviceID string, percent int, exponential bool, exponent float64) error {
if percent < 0 {
return fmt.Errorf("percent out of range: %d", percent)
}
log.Debugf("SetBrightness: %s to %d%%", deviceID, percent)
m.stateMutex.Lock()
currentState := m.state
var found bool
var deviceClass DeviceClass
var deviceIndex int
log.Debugf("Current state has %d devices", len(currentState.Devices))
for i, dev := range currentState.Devices {
if dev.ID == deviceID {
found = true
deviceClass = dev.Class
deviceIndex = i
break
}
}
if !found {
m.stateMutex.Unlock()
log.Debugf("Device not found in state: %s", deviceID)
return fmt.Errorf("device not found: %s", deviceID)
}
newDevices := make([]Device, len(currentState.Devices))
copy(newDevices, currentState.Devices)
newDevices[deviceIndex].CurrentPercent = percent
m.state = State{Devices: newDevices}
m.stateMutex.Unlock()
var err error
if deviceClass == ClassDDC {
log.Debugf("Calling DDC backend for %s", deviceID)
err = m.ddcBackend.SetBrightnessWithExponent(deviceID, percent, exponential, exponent, func() {
m.updateState()
m.debouncedBroadcast(deviceID)
})
} else if m.logindReady && m.logindBackend != nil {
log.Debugf("Calling logind backend for %s", deviceID)
err = m.setViaSysfsWithLogindWithExponent(deviceID, percent, exponential, exponent)
} else {
log.Debugf("Calling sysfs backend for %s", deviceID)
err = m.sysfsBackend.SetBrightnessWithExponent(deviceID, percent, exponential, exponent)
}
if err != nil {
m.updateState()
return fmt.Errorf("failed to set brightness: %w", err)
}
if deviceClass != ClassDDC {
log.Debugf("Queueing broadcast for %s", deviceID)
m.debouncedBroadcast(deviceID)
}
return nil
}
func (m *Manager) IncrementBrightness(deviceID string, step int) error {
return m.IncrementBrightnessWithMode(deviceID, step, m.exponential)
}
func (m *Manager) IncrementBrightnessWithMode(deviceID string, step int, exponential bool) error {
return m.IncrementBrightnessWithExponent(deviceID, step, exponential, 1.2)
}
func (m *Manager) IncrementBrightnessWithExponent(deviceID string, step int, exponential bool, exponent float64) error {
m.stateMutex.RLock()
currentState := m.state
m.stateMutex.RUnlock()
var currentPercent int
var found bool
for _, dev := range currentState.Devices {
if dev.ID == deviceID {
currentPercent = dev.CurrentPercent
found = true
break
}
}
if !found {
return fmt.Errorf("device not found: %s", deviceID)
}
newPercent := currentPercent + step
if newPercent > 100 {
newPercent = 100
}
if newPercent < 0 {
newPercent = 0
}
return m.SetBrightnessWithExponent(deviceID, newPercent, exponential, exponent)
}
func (m *Manager) DecrementBrightness(deviceID string, step int) error {
return m.IncrementBrightness(deviceID, -step)
}
func (m *Manager) setViaSysfsWithLogindWithExponent(deviceID string, percent int, exponential bool, exponent float64) error {
parts := strings.SplitN(deviceID, ":", 2)
if len(parts) != 2 {
return fmt.Errorf("invalid device id: %s", deviceID)
}
subsystem := parts[0]
name := parts[1]
dev, err := m.sysfsBackend.GetDevice(deviceID)
if err != nil {
return err
}
value := m.sysfsBackend.PercentToValueWithExponent(percent, dev, exponential, exponent)
if m.logindBackend == nil {
return m.sysfsBackend.SetBrightnessWithExponent(deviceID, percent, exponential, exponent)
}
err = m.logindBackend.SetBrightness(subsystem, name, uint32(value))
if err != nil {
log.Debugf("logind SetBrightness failed, falling back to direct sysfs: %v", err)
return m.sysfsBackend.SetBrightnessWithExponent(deviceID, percent, exponential, exponent)
}
log.Debugf("set %s to %d%% (%d/%d) via logind", deviceID, percent, value, dev.maxBrightness)
return nil
}
func (m *Manager) debouncedBroadcast(deviceID string) {
m.broadcastMutex.Lock()
defer m.broadcastMutex.Unlock()
m.broadcastPending = true
m.pendingDeviceID = deviceID
if m.broadcastTimer == nil {
m.broadcastTimer = time.AfterFunc(150*time.Millisecond, func() {
m.broadcastMutex.Lock()
pending := m.broadcastPending
deviceID := m.pendingDeviceID
m.broadcastPending = false
m.pendingDeviceID = ""
m.broadcastMutex.Unlock()
if !pending || deviceID == "" {
return
}
m.broadcastDeviceUpdate(deviceID)
})
} else {
m.broadcastTimer.Reset(150 * time.Millisecond)
}
}
func (m *Manager) broadcastDeviceUpdate(deviceID string) {
m.stateMutex.RLock()
var targetDevice *Device
for _, dev := range m.state.Devices {
if dev.ID == deviceID {
devCopy := dev
targetDevice = &devCopy
break
}
}
m.stateMutex.RUnlock()
if targetDevice == nil {
log.Debugf("Device not found for broadcast: %s", deviceID)
return
}
update := DeviceUpdate{Device: *targetDevice}
m.subMutex.RLock()
defer m.subMutex.RUnlock()
if len(m.updateSubscribers) == 0 {
log.Debugf("No update subscribers for device: %s", deviceID)
return
}
log.Debugf("Broadcasting device update: %s at %d%%", deviceID, targetDevice.CurrentPercent)
for _, ch := range m.updateSubscribers {
select {
case ch <- update:
default:
}
}
}