package main import ( "fmt" "io/ioutil" "os" "os/exec" "path/filepath" "strings" "syscall" "time" "unsafe" "github.com/getlantern/systray" "golang.org/x/sys/windows/registry" ) // Define required structures for OS version check const ( VER_MAJORVERSION = 0x001 VER_MINORVERSION = 0x002 VER_BUILDNUMBER = 0x004 ) type RTL_OSVERSIONINFOW struct { OSVersionInfoSize uint32 MajorVersion uint32 MinorVersion uint32 BuildNumber uint32 PlatformId uint32 CSDVersion [128]uint16 } // isWindows11OrNewer checks if the OS is Windows 11 (Build >= 22000) or later. func isWindows11OrNewer() bool { ntdll := syscall.NewLazyDLL("ntdll.dll") rtlGetVersion := ntdll.NewProc("RtlGetVersion") var info RTL_OSVERSIONINFOW info.OSVersionInfoSize = uint32(unsafe.Sizeof(info)) ret, _, _ := rtlGetVersion.Call(uintptr(unsafe.Pointer(&info))) // Check if the call was successful (NTSTATUS 0) if ret != 0 { return false // Assume older or error } // Windows 11 is generally defined by Build Number >= 22000 return info.MajorVersion >= 10 && info.BuildNumber >= 22000 } // Set Windows dark/light mode via registry func setMode(light bool) { key, _ := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Themes\Personalize`, registry.SET_VALUE) defer key.Close() val := uint32(0) if light { val = 1 } key.SetDWordValue("AppsUseLightTheme", val) key.SetDWordValue("SystemUsesLightTheme", val) } // Restart Explorer to fully apply theme func restartExplorer() { exec.Command("taskkill", "/f", "/im", "explorer.exe").Run() time.Sleep(5 * time.Second) exec.Command("explorer.exe").Start() } // Get current theme mode from registry func getCurrentMode() string { key, _ := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Themes\Personalize`, registry.QUERY_VALUE) defer key.Close() val, _, _ := key.GetIntegerValue("AppsUseLightTheme") if val == 1 { return "light" } return "dark" } // Find image in same dir with any supported extension func findImageFile(name string) string { exePath, _ := os.Executable() dir := filepath.Dir(exePath) matches, _ := filepath.Glob(filepath.Join(dir, name+".*")) for _, f := range matches { ext := strings.ToLower(filepath.Ext(f)) if ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".bmp" || ext == ".webp" { return f } } return "" } // Get current wallpaper path from registry func getCurrentWallpaper() string { key, _ := registry.OpenKey(registry.CURRENT_USER, `Control Panel\Desktop`, registry.QUERY_VALUE) defer key.Close() val, _, _ := key.GetStringValue("Wallpaper") return val } // Set desktop wallpaper via Windows API func setWallpaper(path string) { user32 := syscall.NewLazyDLL("user32.dll") sysParam := user32.NewProc("SystemParametersInfoW") p, _ := syscall.UTF16PtrFromString(path) sysParam.Call(0x0014, 0, uintptr(unsafe.Pointer(p)), uintptr(0x01|0x02)) } // Main background loop func backgroundLoop() { lightImg := findImageFile("light") darkImg := findImageFile("dark") lastMode := getCurrentMode() // Determine if explorer restart is needed once at startup needsExplorerRestart := isWindows11OrNewer() if !needsExplorerRestart { fmt.Println("Running on Windows 10 (or older), skipping explorer restart.") } else { fmt.Println("Running on Windows 11 (or newer), explorer restart enabled.") } for { hour := time.Now().Hour() newMode := "dark" var targetImg string if hour >= 6 && hour < 18 { newMode = "light" targetImg = lightImg } else { targetImg = darkImg } if newMode != lastMode { setMode(newMode == "light") // Conditional Explorer Restart ( Windows 10 or 11) if needsExplorerRestart { restartExplorer() } lastMode = newMode } if targetImg != "" && getCurrentWallpaper() != targetImg { setWallpaper(targetImg) } time.Sleep(60 * time.Second) } } // Load icon from local directory (icon.ico) func getIconBytes() []byte { exePath, _ := os.Executable() iconPath := filepath.Join(filepath.Dir(exePath), "icon.ico") data, err := ioutil.ReadFile(iconPath) if err != nil { fmt.Println("icon.ico not found or unreadable.") return nil } return data } // Systray startup func onReady() { icon := getIconBytes() if icon != nil { systray.SetIcon(icon) } systray.SetTitle("Auto Theme") systray.SetTooltip("Auto Theme + Wallpaper Switcher") mQuit := systray.AddMenuItem("Quit", "Exit the program") go func() { go backgroundLoop() <-mQuit.ClickedCh systray.Quit() }() } func onExit() {} func main() { systray.Run(onReady, onExit) }