mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
304 lines
8.1 KiB
Go
304 lines
8.1 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/AvengeMedia/DankMaterialShell/backend/internal/log"
|
|
"github.com/AvengeMedia/DankMaterialShell/backend/internal/server/brightness"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var brightnessCmd = &cobra.Command{
|
|
Use: "brightness",
|
|
Short: "Control device brightness",
|
|
Long: "Control brightness for backlight and LED devices (use --ddc to include DDC/I2C monitors)",
|
|
}
|
|
|
|
var brightnessListCmd = &cobra.Command{
|
|
Use: "list",
|
|
Short: "List all brightness devices",
|
|
Long: "List all available brightness devices with their current values",
|
|
Run: runBrightnessList,
|
|
}
|
|
|
|
var brightnessSetCmd = &cobra.Command{
|
|
Use: "set <device_id> <percent>",
|
|
Short: "Set brightness for a device",
|
|
Long: "Set brightness percentage (0-100) for a specific device",
|
|
Args: cobra.ExactArgs(2),
|
|
Run: runBrightnessSet,
|
|
}
|
|
|
|
var brightnessGetCmd = &cobra.Command{
|
|
Use: "get <device_id>",
|
|
Short: "Get brightness for a device",
|
|
Long: "Get current brightness percentage for a specific device",
|
|
Args: cobra.ExactArgs(1),
|
|
Run: runBrightnessGet,
|
|
}
|
|
|
|
func init() {
|
|
brightnessListCmd.Flags().Bool("ddc", false, "Include DDC/I2C monitors (slower)")
|
|
brightnessSetCmd.Flags().Bool("ddc", false, "Include DDC/I2C monitors (slower)")
|
|
brightnessSetCmd.Flags().Bool("exponential", false, "Use exponential brightness scaling")
|
|
brightnessSetCmd.Flags().Float64("exponent", 1.2, "Exponent for exponential scaling (default 1.2)")
|
|
brightnessGetCmd.Flags().Bool("ddc", false, "Include DDC/I2C monitors (slower)")
|
|
|
|
brightnessCmd.SetHelpTemplate(`{{.Long}}
|
|
|
|
Usage:
|
|
{{.UseLine}}{{if .HasAvailableSubCommands}}
|
|
|
|
Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
|
|
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
|
|
|
|
Flags:
|
|
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
|
|
|
|
Global Flags:
|
|
{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}
|
|
|
|
Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
|
|
{{rpad .Name .NamePadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
|
|
|
|
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
|
|
`)
|
|
|
|
brightnessListCmd.SetHelpTemplate(`{{.Long}}
|
|
|
|
Usage:
|
|
{{.UseLine}}{{if .HasAvailableLocalFlags}}
|
|
|
|
Flags:
|
|
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
|
|
|
|
Global Flags:
|
|
{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}
|
|
`)
|
|
|
|
brightnessSetCmd.SetHelpTemplate(`{{.Long}}
|
|
|
|
Usage:
|
|
{{.UseLine}}{{if .HasAvailableLocalFlags}}
|
|
|
|
Flags:
|
|
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
|
|
|
|
Global Flags:
|
|
{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}
|
|
`)
|
|
|
|
brightnessGetCmd.SetHelpTemplate(`{{.Long}}
|
|
|
|
Usage:
|
|
{{.UseLine}}{{if .HasAvailableLocalFlags}}
|
|
|
|
Flags:
|
|
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
|
|
|
|
Global Flags:
|
|
{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}
|
|
`)
|
|
|
|
brightnessCmd.AddCommand(brightnessListCmd, brightnessSetCmd, brightnessGetCmd)
|
|
}
|
|
|
|
func runBrightnessList(cmd *cobra.Command, args []string) {
|
|
includeDDC, _ := cmd.Flags().GetBool("ddc")
|
|
|
|
allDevices := []brightness.Device{}
|
|
|
|
sysfs, err := brightness.NewSysfsBackend()
|
|
if err != nil {
|
|
log.Debugf("Failed to initialize sysfs backend: %v", err)
|
|
} else {
|
|
devices, err := sysfs.GetDevices()
|
|
if err != nil {
|
|
log.Debugf("Failed to get sysfs devices: %v", err)
|
|
} else {
|
|
allDevices = append(allDevices, devices...)
|
|
}
|
|
}
|
|
|
|
if includeDDC {
|
|
ddc, err := brightness.NewDDCBackend()
|
|
if err != nil {
|
|
fmt.Printf("Warning: Failed to initialize DDC backend: %v\n", err)
|
|
} else {
|
|
time.Sleep(100 * time.Millisecond)
|
|
devices, err := ddc.GetDevices()
|
|
if err != nil {
|
|
fmt.Printf("Warning: Failed to get DDC devices: %v\n", err)
|
|
} else {
|
|
allDevices = append(allDevices, devices...)
|
|
}
|
|
ddc.Close()
|
|
}
|
|
}
|
|
|
|
if len(allDevices) == 0 {
|
|
fmt.Println("No brightness devices found")
|
|
return
|
|
}
|
|
|
|
maxIDLen := len("Device")
|
|
maxNameLen := len("Name")
|
|
for _, dev := range allDevices {
|
|
if len(dev.ID) > maxIDLen {
|
|
maxIDLen = len(dev.ID)
|
|
}
|
|
if len(dev.Name) > maxNameLen {
|
|
maxNameLen = len(dev.Name)
|
|
}
|
|
}
|
|
|
|
idPad := maxIDLen + 2
|
|
namePad := maxNameLen + 2
|
|
|
|
fmt.Printf("%-*s %-12s %-*s %s\n", idPad, "Device", "Class", namePad, "Name", "Brightness")
|
|
|
|
sepLen := idPad + 2 + 12 + 2 + namePad + 2 + 15
|
|
for i := 0; i < sepLen; i++ {
|
|
fmt.Print("─")
|
|
}
|
|
fmt.Println()
|
|
|
|
for _, device := range allDevices {
|
|
fmt.Printf("%-*s %-12s %-*s %3d%%\n",
|
|
idPad,
|
|
device.ID,
|
|
device.Class,
|
|
namePad,
|
|
device.Name,
|
|
device.CurrentPercent,
|
|
)
|
|
}
|
|
}
|
|
|
|
func runBrightnessSet(cmd *cobra.Command, args []string) {
|
|
deviceID := args[0]
|
|
var percent int
|
|
if _, err := fmt.Sscanf(args[1], "%d", &percent); err != nil {
|
|
log.Fatalf("Invalid percent value: %s", args[1])
|
|
}
|
|
|
|
if percent < 0 || percent > 100 {
|
|
log.Fatalf("Percent must be between 0 and 100")
|
|
}
|
|
|
|
includeDDC, _ := cmd.Flags().GetBool("ddc")
|
|
exponential, _ := cmd.Flags().GetBool("exponential")
|
|
exponent, _ := cmd.Flags().GetFloat64("exponent")
|
|
|
|
// For backlight/leds devices, try logind backend first (requires D-Bus connection)
|
|
parts := strings.SplitN(deviceID, ":", 2)
|
|
if len(parts) == 2 && (parts[0] == "backlight" || parts[0] == "leds") {
|
|
subsystem := parts[0]
|
|
name := parts[1]
|
|
|
|
// Initialize backends needed for logind approach
|
|
sysfs, err := brightness.NewSysfsBackend()
|
|
if err != nil {
|
|
log.Debugf("NewSysfsBackend failed: %v", err)
|
|
} else {
|
|
logind, err := brightness.NewLogindBackend()
|
|
if err != nil {
|
|
log.Debugf("NewLogindBackend failed: %v", err)
|
|
} else {
|
|
defer logind.Close()
|
|
|
|
// Get device info to convert percent to value
|
|
dev, err := sysfs.GetDevice(deviceID)
|
|
if err == nil {
|
|
// Calculate hardware value using the same logic as Manager.setViaSysfsWithLogind
|
|
value := sysfs.PercentToValueWithExponent(percent, dev, exponential, exponent)
|
|
|
|
// Call logind with hardware value
|
|
if err := logind.SetBrightness(subsystem, name, uint32(value)); err == nil {
|
|
log.Debugf("set %s to %d%% (%d) via logind", deviceID, percent, value)
|
|
fmt.Printf("Set %s to %d%%\n", deviceID, percent)
|
|
return
|
|
} else {
|
|
log.Debugf("logind.SetBrightness failed: %v", err)
|
|
}
|
|
} else {
|
|
log.Debugf("sysfs.GetDeviceByID failed: %v", err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fallback to direct sysfs (requires write permissions)
|
|
sysfs, err := brightness.NewSysfsBackend()
|
|
if err == nil {
|
|
if err := sysfs.SetBrightnessWithExponent(deviceID, percent, exponential, exponent); err == nil {
|
|
fmt.Printf("Set %s to %d%%\n", deviceID, percent)
|
|
return
|
|
}
|
|
log.Debugf("sysfs.SetBrightness failed: %v", err)
|
|
} else {
|
|
log.Debugf("NewSysfsBackend failed: %v", err)
|
|
}
|
|
|
|
// Try DDC if requested
|
|
if includeDDC {
|
|
ddc, err := brightness.NewDDCBackend()
|
|
if err == nil {
|
|
defer ddc.Close()
|
|
time.Sleep(100 * time.Millisecond)
|
|
if err := ddc.SetBrightnessWithExponent(deviceID, percent, exponential, exponent, nil); err == nil {
|
|
fmt.Printf("Set %s to %d%%\n", deviceID, percent)
|
|
return
|
|
}
|
|
log.Debugf("ddc.SetBrightness failed: %v", err)
|
|
} else {
|
|
log.Debugf("NewDDCBackend failed: %v", err)
|
|
}
|
|
}
|
|
|
|
log.Fatalf("Failed to set brightness for device: %s", deviceID)
|
|
}
|
|
|
|
func runBrightnessGet(cmd *cobra.Command, args []string) {
|
|
deviceID := args[0]
|
|
includeDDC, _ := cmd.Flags().GetBool("ddc")
|
|
|
|
allDevices := []brightness.Device{}
|
|
|
|
sysfs, err := brightness.NewSysfsBackend()
|
|
if err == nil {
|
|
devices, err := sysfs.GetDevices()
|
|
if err == nil {
|
|
allDevices = append(allDevices, devices...)
|
|
}
|
|
}
|
|
|
|
if includeDDC {
|
|
ddc, err := brightness.NewDDCBackend()
|
|
if err == nil {
|
|
defer ddc.Close()
|
|
time.Sleep(100 * time.Millisecond)
|
|
devices, err := ddc.GetDevices()
|
|
if err == nil {
|
|
allDevices = append(allDevices, devices...)
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, device := range allDevices {
|
|
if device.ID == deviceID {
|
|
fmt.Printf("%s: %d%% (%d/%d)\n",
|
|
device.ID,
|
|
device.CurrentPercent,
|
|
device.Current,
|
|
device.Max,
|
|
)
|
|
return
|
|
}
|
|
}
|
|
|
|
log.Fatalf("Device not found: %s", deviceID)
|
|
}
|