/// <summary> /// checks if any theme needs an update because the runtimeconfig differs from the actual configured state /// </summary> /// <param name="config">AutoDarkModeConfig instance</param> /// <param name="newTheme">new theme that is requested</param> /// <returns></returns> private static bool ThemeOptionsNeedUpdate(AdmConfig config, Theme newTheme) { RuntimeConfig rtc = RuntimeConfig.Instance(); if (config.Wallpaper.Enabled) { if (rtc.CurrentWallpaperTheme == Theme.Undefined || rtc.CurrentWallpaperTheme != newTheme) { return(true); } } if (config.SystemTheme != Mode.LightOnly) { // if accent color is enabled in config, accent color is enabled in windows // and the target theme is light we need to update if (config.AccentColorTaskbarEnabled && rtc.CurrentColorPrevalence && newTheme == Theme.Light) { return(true); } // if accent color is enabled in config, but it's not currently active, update else if (config.AccentColorTaskbarEnabled && !rtc.CurrentColorPrevalence) { return(true); } // if accent color is disabled in config but still active, we need to disable it else if (!config.AccentColorTaskbarEnabled && rtc.CurrentColorPrevalence) { return(true); } } if (ComponentNeedsUpdate(config.SystemTheme, rtc.CurrentSystemTheme, newTheme)) { return(true); } if (ComponentNeedsUpdate(config.AppsTheme, rtc.CurrentAppsTheme, newTheme)) { return(true); } if (ComponentNeedsUpdate(config.EdgeTheme, rtc.CurrentEdgeTheme, newTheme)) { return(true); } if (WallpaperNeedsUpdate(config.Wallpaper.Enabled, rtc.CurrentWallpaperPath, config.Wallpaper.LightThemeWallpapers, config.Wallpaper.DarkThemeWallpapers, rtc.CurrentWallpaperTheme, newTheme)) { return(true); } if (config.Office.Enabled && ComponentNeedsUpdate(config.Office.Mode, rtc.CurrentOfficeTheme, newTheme)) { return(true); } if (config.ColorFilterEnabled && ColorFilterNeedsUpdate(config.ColorFilterEnabled, rtc.ColorFilterEnabled, newTheme)) { return(true); } return(false); }
/// <summary> /// Parses a command message and invokes a callback function delegate for status reporting /// </summary> /// <param name="msg">list of messages to parse</param> /// <param name="SendResponse">Callback taking a string as parameter to report return values back to sender</param> /// <param name="service">Service class for invoking application exit</param> public static void Parse(List <string> msg, Action <string> SendResponse, Service service) { AdmConfigBuilder builder = AdmConfigBuilder.Instance(); RuntimeConfig rtc = RuntimeConfig.Instance(); msg.ForEach(message => { switch (message) { case Command.Switch: Logger.Info("signal received: time based theme switch"); ThemeManager.TimedSwitch(builder); SendResponse(Response.Ok); break; case Command.Swap: Logger.Info("signal received: swap themes"); if (RegistryHandler.AppsUseLightTheme()) { ThemeManager.SwitchTheme(builder.Config, Theme.Dark); } else { ThemeManager.SwitchTheme(builder.Config, Theme.Light); } SendResponse(Response.Ok); break; case Command.AddAutostart: Logger.Info("signal received: adding service to autostart"); bool regOk; bool taskOk; if (builder.Config.Tunable.UseLogonTask) { regOk = RegistryHandler.RemoveAutoStart(); taskOk = TaskSchdHandler.CreateLogonTask(); } else { taskOk = TaskSchdHandler.RemoveLogonTask(); regOk = RegistryHandler.AddAutoStart(); } if (regOk && taskOk) { SendResponse(Response.Ok); } else { SendResponse(Response.Err); } break; case Command.RemoveAutostart: Logger.Info("signal received: removing service from autostart"); bool ok; if (builder.Config.Tunable.UseLogonTask) { ok = TaskSchdHandler.RemoveLogonTask(); } else { ok = RegistryHandler.RemoveAutoStart(); } if (ok) { SendResponse(Response.Ok); } else { SendResponse(Response.Err); } break; case Command.Location: Logger.Info("signal received: request location update"); Task <bool> geoTask = Task.Run(() => LocationHandler.UpdateGeoposition(AdmConfigBuilder.Instance())); geoTask.Wait(); var result = geoTask.Result; if (result) { SendResponse(Response.Ok); } else { SendResponse(Response.NoLocAccess); } break; case Command.UpdateConfig: Logger.Info("signal received: updating configuration files"); try { AdmConfigBuilder.Instance().Load(); AdmConfigBuilder.Instance().LoadLocationData(); SendResponse(Response.Ok); } catch (Exception e) { Logger.Error(e, "could not read config file"); SendResponse(Response.Err); } break; case Command.Update: Logger.Info("signal received: checking for update"); SendResponse(UpdateHandler.CheckNewVersion()); break; case Command.Shutdown: Logger.Info("signal received, exiting"); SendResponse(Response.Ok); service.Exit(null, null); break; case Command.TestError: Logger.Info("signal received: test error"); SendResponse(Response.Err); break; case Command.Alive: Logger.Info("signal received: request for running status"); SendResponse(Response.Ok); break; case Command.Light: Logger.Info("signal received: force light theme"); rtc.ForcedTheme = Theme.Light; ThemeManager.SwitchTheme(builder.Config, Theme.Light); SendResponse(Response.Ok); break; case Command.Dark: Logger.Info("signal received: force dark theme"); rtc.ForcedTheme = Theme.Dark; ThemeManager.SwitchTheme(builder.Config, Theme.Dark); SendResponse(Response.Ok); break; case Command.NoForce: Logger.Info("signal received: resetting forced modes"); rtc.ForcedTheme = Theme.Undefined; ThemeManager.TimedSwitch(builder); SendResponse(Response.Ok); break; default: Logger.Debug("unknown message received"); SendResponse(Response.Err); break; } }); }
/// <summary> /// Parses a command message and invokes a callback function delegate for status reporting /// </summary> /// <param name="msg">list of messages to parse</param> /// <param name="SendResponse">Callback taking a string as parameter to report return values back to sender</param> /// <param name="service">Service class for invoking application exit</param> public static void Parse(List <string> msg, Action <string> SendResponse, Service service) { AdmConfigBuilder Properties = AdmConfigBuilder.Instance(); RuntimeConfig rtc = RuntimeConfig.Instance(); msg.ForEach(message => { switch (message) { case Command.Switch: Logger.Info("signal received: time based theme switch"); ThemeManager.TimedSwitch(Properties); SendResponse(Command.Ok); break; case Command.Swap: Logger.Info("signal received: swap themes"); if (RegistryHandler.AppsUseLightTheme()) { ThemeManager.SwitchTheme(Properties.Config, Theme.Dark); } else { ThemeManager.SwitchTheme(Properties.Config, Theme.Light); } SendResponse(Command.Ok); break; case Command.AddAutostart: Logger.Info("signal received: adding service to autostart"); RegistryHandler.AddAutoStart(); SendResponse(Command.Ok); break; case Command.RemoveAutostart: Logger.Info("signal received: removing service from autostart"); RegistryHandler.RemoveAutoStart(); SendResponse(Command.Ok); break; case Command.CreateTask: Logger.Info("signal received: creating win scheduler based time switch task"); try { DateTime sunrise = Convert.ToDateTime(Properties.Config.Sunrise); DateTime sunset = Convert.ToDateTime(Properties.Config.Sunset); if (Properties.Config.Location.Enabled) { LocationHandler.GetSunTimesWithOffset(Properties, out sunrise, out sunset); } TaskSchdHandler.CreateSwitchTask(sunrise.Hour, sunrise.Minute, sunset.Hour, sunset.Minute); SendResponse(Command.Ok); } catch (FormatException e) { Logger.Error(e, "could not create win scheduler tasks"); SendResponse(Command.Err); Console.WriteLine(e); } break; case Command.RemoveTask: Logger.Info("signal received: removing win tasks"); TaskSchdHandler.RemoveTasks(); SendResponse(Command.Ok); break; case Command.Location: Logger.Info("signal received: request location update"); Task <bool> geoTask = Task.Run(() => LocationHandler.UpdateGeoposition(AdmConfigBuilder.Instance())); geoTask.Wait(); var result = geoTask.Result; if (result) { SendResponse(Command.Ok); } else { SendResponse(Command.NoLocAccess); } break; case Command.UpdateConfig: Logger.Info("signal received: updating configuration files"); try { AdmConfigBuilder.Instance().Load(); AdmConfigBuilder.Instance().LoadLocationData(); SendResponse(Command.Ok); } catch (Exception e) { Logger.Error(e, "could not read config file"); SendResponse(Command.Err); } break; case Command.Update: Logger.Info("signal received: checking for update"); SendResponse(UpdateHandler.CheckNewVersion()); break; case Command.Shutdown: Logger.Info("signal received, exiting"); SendResponse(Command.Ok); service.Exit(null, null); break; case Command.TestError: Logger.Info("signal received: test error"); SendResponse(Command.Err); break; case Command.Alive: Logger.Info("signal received: request for running status"); SendResponse(Command.Ok); break; case Command.Light: Logger.Info("signal received: force light theme"); rtc.ForcedTheme = Theme.Light; ThemeManager.SwitchTheme(Properties.Config, Theme.Light); SendResponse(Command.Ok); break; case Command.Dark: Logger.Info("signal received: force dark theme"); rtc.ForcedTheme = Theme.Dark; ThemeManager.SwitchTheme(Properties.Config, Theme.Dark); SendResponse(Command.Ok); break; case Command.NoForce: Logger.Info("signal received: resetting forced modes"); rtc.ForcedTheme = Theme.Undefined; ThemeManager.TimedSwitch(Properties); SendResponse(Command.Ok); break; default: Logger.Debug("unknown message received"); SendResponse(Command.Err); break; } }); }
/// <summary> /// Instantiates a new TimeSwitchModule. /// This module switches themes based on system time and sunrise/sunset /// </summary> /// <param name="name">unique name of the module</param> public ThemeUpdateModule(string name, bool fireOnRegistration) : base(name, fireOnRegistration) { RuntimeConfigInstance = RuntimeConfig.Instance(); }
static void Main(string[] args) { try { //Set up Logger var config = new NLog.Config.LoggingConfiguration(); var configDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AutoDarkMode"); try { Directory.CreateDirectory(configDir); } catch (Exception e) { Logger.Debug(e, "could not create config directory"); } // Targets where to log to: File and Console var logfile = new NLog.Targets.FileTarget("logfile") { FileName = Path.Combine(configDir, "service.log"), Layout = @"${date:format=yyyy-MM-dd HH\:mm\:ss} | ${level} | " + "${callsite:includeNamespace=False:" + "cleanNamesOfAnonymousDelegates=true:" + "cleanNamesOfAsyncContinuations=true}: ${message} ${exception:separator=|}" }; var logconsole = new NLog.Targets.ColoredConsoleTarget("logconsole") { Layout = @"${date:format=yyyy-MM-dd HH\:mm\:ss} | ${level} | " + "${callsite:includeNamespace=False:" + "cleanNamesOfAnonymousDelegates=true:" + "cleanNamesOfAsyncContinuations=true}: ${message} ${exception:separator=|}" }; List <string> argsList; if (args.Length > 0) { argsList = new List <string>(args); } else { argsList = new List <string>(); } // Rules for mapping loggers to targets config.AddRule(LogLevel.Debug, LogLevel.Fatal, logconsole); if (argsList.Contains("/debug")) { config.AddRule(LogLevel.Debug, LogLevel.Fatal, logfile); } else { config.AddRule(LogLevel.Info, LogLevel.Fatal, logfile); } // Apply config LogManager.Configuration = config; if (!mutex.WaitOne(TimeSpan.FromSeconds(2), false)) { Logger.Debug("app instance already open"); return; } //Instantiate Runtime config RuntimeConfig.Instance(); //Populate configuration AdmConfigBuilder Builder = AdmConfigBuilder.Instance(); try { Builder.Load(); Builder.LoadLocationData(); Logger.Debug("config builder instantiated and configuration loaded"); } catch (Exception e) { Logger.Fatal(e, "could not read config file. shutting down application!"); NLog.LogManager.Shutdown(); System.Environment.Exit(-1); } //if a path is set to null, set it to the currently actvie theme for convenience reasons bool configUpdateNeeded = false; if (!File.Exists(Builder.Config.DarkThemePath) || Builder.Config.DarkThemePath == null) { Builder.Config.DarkThemePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Microsoft\Windows\Themes", ThemeHandler.GetCurrentThemeName() + ".theme"); configUpdateNeeded = true; } if (!File.Exists(Builder.Config.DarkThemePath) || Builder.Config.LightThemePath == null) { Builder.Config.LightThemePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Microsoft\Windows\Themes", ThemeHandler.GetCurrentThemeName() + ".theme"); configUpdateNeeded = true; } if (configUpdateNeeded) { Logger.Warn("one or more theme paths not set at program start, reinstantiation needed"); try { Builder.Save(); } catch (Exception ex) { Logger.Error(ex, "couldn't save configuration file"); } } int timerMillis = 0; if (args.Length != 0) { Int32.TryParse(args[0], out timerMillis); } timerMillis = (timerMillis == 0) ? TimerFrequency.Short : timerMillis; Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Service = new Service(timerMillis); Application.Run(Service); } finally { //clean shutdown if (Service != null) { Service.Cleanup(); } mutex.Dispose(); } }