Change how settings and tray are handled.
This commit is contained in:
parent
1347223707
commit
af4ec9ad8b
|
@ -1,41 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Espresso.Shell.Core
|
||||
{
|
||||
public class SettingsHelper
|
||||
{
|
||||
const int ERROR_SHARING_VIOLATION = 32;
|
||||
const int ERROR_LOCK_VIOLATION = 33;
|
||||
|
||||
public static FileStream? GetSettingsFile(string path, int retries)
|
||||
{
|
||||
for (int i = 0; i < retries; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None);
|
||||
return fileStream;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
var errorCode = Marshal.GetHRForException(ex) & ((1 << 16) - 1);
|
||||
if (errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION)
|
||||
{
|
||||
Console.WriteLine("There was another process using the file, so couldn't pick the settings up.");
|
||||
}
|
||||
|
||||
Thread.Sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,36 +2,76 @@
|
|||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Espresso.Shell.Models;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
|
||||
namespace Espresso.Shell.Core
|
||||
{
|
||||
internal static class TrayHelper
|
||||
{
|
||||
static NotifyIcon trayIcon;
|
||||
static NotifyIcon? trayIcon;
|
||||
private static NotifyIcon TrayIcon { get => trayIcon; set => trayIcon = value; }
|
||||
|
||||
static SettingsUtils? moduleSettings;
|
||||
private static SettingsUtils ModuleSettings { get => moduleSettings; set => moduleSettings = value; }
|
||||
|
||||
static TrayHelper()
|
||||
{
|
||||
trayIcon = new NotifyIcon();
|
||||
TrayIcon = new NotifyIcon();
|
||||
ModuleSettings = new SettingsUtils();
|
||||
}
|
||||
|
||||
private static void InitializeTrayIcon(string text, Icon icon, ContextMenuStrip contextMenu)
|
||||
public static void InitializeTray(string text, Icon icon, ContextMenuStrip? contextMenu)
|
||||
{
|
||||
trayIcon.Text = text;
|
||||
trayIcon.Icon = icon;
|
||||
trayIcon.ContextMenuStrip = contextMenu;
|
||||
trayIcon.Visible = true;
|
||||
System.Threading.Tasks.Task.Factory.StartNew((tray) =>
|
||||
{
|
||||
((NotifyIcon?)tray).Text = text;
|
||||
((NotifyIcon?)tray).Icon = icon;
|
||||
((NotifyIcon?)tray).ContextMenuStrip = contextMenu;
|
||||
((NotifyIcon?)tray).Visible = true;
|
||||
|
||||
Application.Run();
|
||||
Application.Run();
|
||||
}, TrayIcon);
|
||||
}
|
||||
|
||||
internal static void InitializeEspressoTray(string text, EspressoMode mode, bool keepDisplayOn, Action indefiniteSelectionCallback, Action timedSelectionCallback)
|
||||
internal static void SetTray(string text, EspressoSettings settings)
|
||||
{
|
||||
SetTray(text, settings.Properties.KeepDisplayOn.Value, settings.Properties.Mode, settings.Properties.Hours.Value, settings.Properties.Minutes.Value,
|
||||
() => {
|
||||
// Set indefinite keep awake.
|
||||
var currentSettings = ModuleSettings.GetSettings<EspressoSettings>(text);
|
||||
currentSettings.Properties.Mode = EspressoMode.INDEFINITE;
|
||||
ModuleSettings.SaveSettings(JsonConvert.SerializeObject(currentSettings), text);
|
||||
},
|
||||
() => {
|
||||
// Set timed keep awake.
|
||||
var currentSettings = ModuleSettings.GetSettings<EspressoSettings>(text);
|
||||
currentSettings.Properties.Mode = EspressoMode.TIMED;
|
||||
currentSettings.Properties.Hours.Value = settings.Properties.Hours.Value;
|
||||
currentSettings.Properties.Minutes.Value = settings.Properties.Minutes.Value;
|
||||
|
||||
ModuleSettings.SaveSettings(JsonConvert.SerializeObject(currentSettings), text);
|
||||
},
|
||||
() =>
|
||||
{
|
||||
// Just changing the display mode.
|
||||
var currentSettings = ModuleSettings.GetSettings<EspressoSettings>(text);
|
||||
currentSettings.Properties.KeepDisplayOn = settings.Properties.KeepDisplayOn;
|
||||
|
||||
ModuleSettings.SaveSettings(JsonConvert.SerializeObject(currentSettings), text);
|
||||
});
|
||||
}
|
||||
|
||||
internal static void SetTray(string text, bool keepDisplayOn, EspressoMode mode, int hours, int minutes, Action indefiniteKeepAwakeCallback, Action timedKeepAwakeCallback, Action keepDisplayOnCallback)
|
||||
{
|
||||
var contextMenuStrip = new ContextMenuStrip();
|
||||
|
||||
|
||||
// Main toolstrip.
|
||||
var operationContextMenu = new ToolStripMenuItem();
|
||||
operationContextMenu.Text = "Mode";
|
||||
|
@ -39,10 +79,28 @@ namespace Espresso.Shell.Core
|
|||
// Indefinite keep-awake menu item.
|
||||
var indefiniteMenuItem = new ToolStripMenuItem();
|
||||
indefiniteMenuItem.Text = "Indefinite";
|
||||
|
||||
if (mode == EspressoMode.INDEFINITE)
|
||||
{
|
||||
indefiniteMenuItem.Checked = true;
|
||||
}
|
||||
indefiniteMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User opted to set the mode to indefinite, so we need to write new settings.
|
||||
indefiniteKeepAwakeCallback();
|
||||
};
|
||||
|
||||
var displayOnMenuItem = new ToolStripMenuItem();
|
||||
displayOnMenuItem.Text = "Keep display on";
|
||||
if (keepDisplayOn)
|
||||
{
|
||||
displayOnMenuItem.Checked = true;
|
||||
}
|
||||
displayOnMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User opted to set the display mode directly.
|
||||
keepDisplayOnCallback();
|
||||
};
|
||||
|
||||
// Timed keep-awake menu item
|
||||
var timedMenuItem = new ToolStripMenuItem();
|
||||
|
@ -50,12 +108,27 @@ namespace Espresso.Shell.Core
|
|||
|
||||
var halfHourMenuItem = new ToolStripMenuItem();
|
||||
halfHourMenuItem.Text = "30 minutes";
|
||||
halfHourMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User is setting the keep-awake to 30 minutes.
|
||||
timedKeepAwakeCallback();
|
||||
};
|
||||
|
||||
var oneHourMenuItem = new ToolStripMenuItem();
|
||||
oneHourMenuItem.Text = "1 hour";
|
||||
oneHourMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User is setting the keep-awake to 1 hour.
|
||||
timedKeepAwakeCallback();
|
||||
};
|
||||
|
||||
var twoHoursMenuItem = new ToolStripMenuItem();
|
||||
twoHoursMenuItem.Text = "2 hours";
|
||||
twoHoursMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User is setting the keep-awake to 2 hours.
|
||||
timedKeepAwakeCallback();
|
||||
};
|
||||
|
||||
timedMenuItem.DropDownItems.Add(halfHourMenuItem);
|
||||
timedMenuItem.DropDownItems.Add(oneHourMenuItem);
|
||||
|
@ -63,12 +136,12 @@ namespace Espresso.Shell.Core
|
|||
|
||||
operationContextMenu.DropDownItems.Add(indefiniteMenuItem);
|
||||
operationContextMenu.DropDownItems.Add(timedMenuItem);
|
||||
operationContextMenu.DropDownItems.Add(new ToolStripSeparator());
|
||||
operationContextMenu.DropDownItems.Add(displayOnMenuItem);
|
||||
|
||||
contextMenuStrip.Items.Add(operationContextMenu);
|
||||
|
||||
#pragma warning disable CS8604 // Possible null reference argument.
|
||||
Task.Factory.StartNew(() => InitializeTrayIcon(text, APIHelper.Extract("shell32.dll", 12, true), contextMenuStrip));
|
||||
#pragma warning restore CS8604 // Possible null reference argument.
|
||||
TrayIcon.ContextMenuStrip = contextMenuStrip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\..\settings-ui\Microsoft.PowerToys.Settings.UI.Library\Microsoft.PowerToys.Settings.UI.Library.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Espresso.Shell.Models
|
||||
{
|
||||
public enum EspressoMode
|
||||
{
|
||||
INDEFINITE = 0,
|
||||
TIMED = 1,
|
||||
}
|
||||
|
||||
public class EspressoSettingsModel
|
||||
{
|
||||
[JsonProperty("properties")]
|
||||
public Properties? Properties { get; set; }
|
||||
[JsonProperty("name")]
|
||||
public string? Name { get; set; }
|
||||
[JsonProperty("version")]
|
||||
public string? Version { get; set; }
|
||||
}
|
||||
|
||||
public class Properties
|
||||
{
|
||||
[JsonProperty("espresso_keep_display_on")]
|
||||
public KeepDisplayOn? KeepDisplayOn { get; set; }
|
||||
[JsonProperty("espresso_mode")]
|
||||
public EspressoMode Mode { get; set; }
|
||||
[JsonProperty("espresso_hours")]
|
||||
public Hours? Hours { get; set; }
|
||||
[JsonProperty("espresso_minutes")]
|
||||
public Minutes? Minutes { get; set; }
|
||||
}
|
||||
|
||||
public class KeepDisplayOn
|
||||
{
|
||||
public bool Value { get; set; }
|
||||
}
|
||||
|
||||
public class Hours
|
||||
{
|
||||
public int Value { get; set; }
|
||||
}
|
||||
|
||||
public class Minutes
|
||||
{
|
||||
public int Value { get; set; }
|
||||
}
|
||||
|
||||
}
|
|
@ -3,8 +3,8 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Espresso.Shell.Core;
|
||||
using Espresso.Shell.Models;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using System;
|
||||
|
@ -19,7 +19,6 @@ using System.Reflection;
|
|||
using System.Threading;
|
||||
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
|
||||
namespace Espresso.Shell
|
||||
|
@ -29,6 +28,7 @@ namespace Espresso.Shell
|
|||
private static Mutex? mutex = null;
|
||||
private const string appName = "Espresso";
|
||||
private static FileSystemWatcher? watcher = null;
|
||||
private static SettingsUtils? settingsUtils = null;
|
||||
|
||||
public static Mutex Mutex { get => mutex; set => mutex = value; }
|
||||
|
||||
|
@ -45,7 +45,8 @@ namespace Espresso.Shell
|
|||
}
|
||||
|
||||
log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
settingsUtils = new SettingsUtils();
|
||||
|
||||
log.Info("Launching Espresso...");
|
||||
log.Info(FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion);
|
||||
log.Debug($"OS: {Environment.OSVersion}");
|
||||
|
@ -158,7 +159,7 @@ namespace Espresso.Shell
|
|||
|
||||
// Initially the file might not be updated, so we need to start processing
|
||||
// settings right away.
|
||||
ProcessSettings(config);
|
||||
ProcessSettings();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -171,23 +172,12 @@ namespace Espresso.Shell
|
|||
{
|
||||
if (timeLimit <= 0)
|
||||
{
|
||||
// Indefinite keep awake.
|
||||
bool success = APIHelper.SetIndefiniteKeepAwake(displayOn);
|
||||
if (success)
|
||||
{
|
||||
log.Info($"Currently in indefinite keep awake. Display always on: {displayOn}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorMessage = "Could not set up the state to be indefinite keep awake.";
|
||||
log.Info(errorMessage);
|
||||
log.Debug(errorMessage);
|
||||
}
|
||||
SetupIndefiniteKeepAwake(displayOn);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Timed keep-awake.
|
||||
APIHelper.SetTimedKeepAwake(timeLimit, LogTimedKeepAwakeCompletion, LogUnexpectedOrCancelledKeepAwakeCompletion, displayOn);
|
||||
SetupTimedKeepAwake(timeLimit, displayOn);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,87 +189,78 @@ namespace Espresso.Shell
|
|||
});
|
||||
}
|
||||
|
||||
TrayHelper.InitializeEspressoTray("Espresso", EspressoMode.INDEFINITE, true, new Action(()=>Console.WriteLine("test")), new Action(() => Console.WriteLine("test")));
|
||||
#pragma warning disable CS8604 // Possible null reference argument.
|
||||
TrayHelper.InitializeTray(appName, APIHelper.Extract("shell32.dll", 21, true), null);
|
||||
#pragma warning restore CS8604 // Possible null reference argument.
|
||||
|
||||
new ManualResetEvent(false).WaitOne();
|
||||
}
|
||||
|
||||
private static void SetupIndefiniteKeepAwake(bool displayOn)
|
||||
{
|
||||
// Indefinite keep awake.
|
||||
bool success = APIHelper.SetIndefiniteKeepAwake(displayOn);
|
||||
if (success)
|
||||
{
|
||||
log.Info($"Currently in indefinite keep awake. Display always on: {displayOn}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorMessage = "Could not set up the state to be indefinite keep awake.";
|
||||
log.Info(errorMessage);
|
||||
log.Debug(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleEspressoConfigChange(FileSystemEventArgs fileEvent)
|
||||
{
|
||||
log.Info("Detected a settings file change. Updating configuration...");
|
||||
log.Info("Resetting keep-awake to normal state due to settings change.");
|
||||
ResetNormalPowerState();
|
||||
ProcessSettings(fileEvent.FullPath);
|
||||
ProcessSettings();
|
||||
}
|
||||
|
||||
private static void ProcessSettings(string fullPath)
|
||||
private static void ProcessSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
EspressoSettingsModel settings = null;
|
||||
EspressoSettings settings = settingsUtils.GetSettings<EspressoSettings>(appName);
|
||||
|
||||
var fileStream = SettingsHelper.GetSettingsFile(fullPath, 3);
|
||||
if (fileStream != null)
|
||||
if (settings != null)
|
||||
{
|
||||
using (fileStream)
|
||||
// If the settings were successfully processed, we need to set the right mode of operation.
|
||||
// INDEFINITE = 0
|
||||
// TIMED = 1
|
||||
switch (settings.Properties.Mode)
|
||||
{
|
||||
using StreamReader reader = new StreamReader(fileStream);
|
||||
case EspressoMode.INDEFINITE:
|
||||
{
|
||||
// Indefinite keep awake.
|
||||
SetupIndefiniteKeepAwake(settings.Properties.KeepDisplayOn.Value);
|
||||
break;
|
||||
}
|
||||
case EspressoMode.TIMED:
|
||||
{
|
||||
// Timed keep-awake.
|
||||
long computedTime = (settings.Properties.Hours.Value * 60 * 60) + (settings.Properties.Minutes.Value * 60);
|
||||
SetupTimedKeepAwake(computedTime, settings.Properties.KeepDisplayOn.Value);
|
||||
|
||||
settings = JsonConvert.DeserializeObject<EspressoSettingsModel>(reader.ReadToEnd());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
var errorMessage = "Unknown mode of operation. Check config file.";
|
||||
log.Info(errorMessage);
|
||||
log.Debug(errorMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
// If the settings were successfully processed, we need to set the right mode of operation.
|
||||
// INDEFINITE = 0
|
||||
// TIMED = 1
|
||||
switch (settings.Properties.Mode)
|
||||
{
|
||||
case EspressoMode.INDEFINITE:
|
||||
{
|
||||
// Indefinite keep awake.
|
||||
bool success = APIHelper.SetIndefiniteKeepAwake(settings.Properties.KeepDisplayOn.Value);
|
||||
if (success)
|
||||
{
|
||||
log.Info($"Indefinite keep-awake. Display always on: {settings.Properties.KeepDisplayOn.Value}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorMessage = "Could not set up the state to be indefinite keep-awake.";
|
||||
log.Info(errorMessage);
|
||||
log.Debug(errorMessage);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EspressoMode.TIMED:
|
||||
{
|
||||
// Timed keep-awake.
|
||||
long computedTime = (settings.Properties.Hours.Value * 60 * 60) + (settings.Properties.Minutes.Value * 60);
|
||||
log.Info($"Timed keep-awake. Expected runtime: {computedTime} seconds.");
|
||||
|
||||
APIHelper.SetTimedKeepAwake(computedTime, LogTimedKeepAwakeCompletion, LogUnexpectedOrCancelledKeepAwakeCompletion, settings.Properties.KeepDisplayOn.Value);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
var errorMessage= "Unknown mode of operation. Check config file.";
|
||||
log.Info(errorMessage);
|
||||
log.Debug(errorMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorMessage = "Settings are null.";
|
||||
log.Info(errorMessage);
|
||||
log.Debug(errorMessage);
|
||||
}
|
||||
TrayHelper.SetTray(appName, settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorMessage = "Could not get handle on file.";
|
||||
var errorMessage = "Settings are null.";
|
||||
log.Info(errorMessage);
|
||||
log.Debug(errorMessage);
|
||||
}
|
||||
|
@ -289,10 +270,16 @@ namespace Espresso.Shell
|
|||
var errorMessage = $"There was a problem reading the configuration file. Error: {ex.Message}";
|
||||
log.Info(errorMessage);
|
||||
log.Debug(errorMessage);
|
||||
log.Debug($"Configuration path: {fullPath}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetupTimedKeepAwake(long time, bool displayOn)
|
||||
{
|
||||
log.Info($"Timed keep-awake. Expected runtime: {time} seconds.");
|
||||
|
||||
APIHelper.SetTimedKeepAwake(time, LogTimedKeepAwakeCompletion, LogUnexpectedOrCancelledKeepAwakeCompletion, displayOn);
|
||||
}
|
||||
|
||||
private static void LogUnexpectedOrCancelledKeepAwakeCompletion()
|
||||
{
|
||||
var errorMessage = "The keep-awake thread was terminated early.";
|
||||
|
|
Loading…
Reference in a new issue