Skip to content

Commit

Permalink
[MouseJump] - add FileSystemWatcher for config (microsoft#26703)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikeclayton committed Sep 27, 2023
1 parent 769045e commit 003c4fa
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 7 deletions.
95 changes: 95 additions & 0 deletions src/modules/MouseUtils/MouseJumpUI/Helpers/SettingsHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// 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.IO.Abstractions;
using System.Threading;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;

namespace MouseJumpUI.Helpers;

internal class SettingsHelper
{
public SettingsHelper()
{
this.LockObject = new();
this.CurrentSettings = this.LoadSettings();

// delay loading settings on change by some time to avoid file in use exception
var throttledActionInvoker = new ThrottledActionInvoker();
this.FileSystemWatcher = Helper.GetFileWatcher(
moduleName: MouseJumpSettings.ModuleName,
fileName: "settings.json",
onChangedCallback: () => throttledActionInvoker.ScheduleAction(this.ReloadSettings, 250));
}

private IFileSystemWatcher FileSystemWatcher
{
get;
}

private object LockObject
{
get;
}

public MouseJumpSettings CurrentSettings
{
get;
private set;
}

private MouseJumpSettings LoadSettings()
{
lock (this.LockObject)
{
{
var settingsUtils = new SettingsUtils();

// set this to 1 to disable retries
var remainingRetries = 5;

while (remainingRetries > 0)
{
try
{
if (!settingsUtils.SettingsExists(MouseJumpSettings.ModuleName))
{
Logger.LogInfo("MouseJump settings.json was missing, creating a new one");
var defaultSettings = new MouseJumpSettings();
defaultSettings.Save(settingsUtils);
}

var settings = settingsUtils.GetSettingsOrDefault<MouseJumpSettings>(MouseJumpSettings.ModuleName);
return settings;
}
catch (IOException ex)
{
Logger.LogError("Failed to read changed settings", ex);
Thread.Sleep(250);
}
catch (Exception ex)
{
Logger.LogError("Failed to read changed settings", ex);
Thread.Sleep(250);
}

remainingRetries--;
}
}
}

const string message = "Failed to read changed settings - ran out of retries";
Logger.LogError(message);
throw new InvalidOperationException(message);
}

public void ReloadSettings()
{
this.CurrentSettings = this.LoadSettings();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// 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.Windows.Threading;

namespace MouseJumpUI.Helpers;

internal sealed class ThrottledActionInvoker
{
private readonly object _invokerLock = new();
private readonly DispatcherTimer _timer;

private Action? _actionToRun;

public ThrottledActionInvoker()
{
_timer = new DispatcherTimer();
_timer.Tick += Timer_Tick;
}

public void ScheduleAction(Action action, int milliseconds)
{
lock (_invokerLock)
{
if (_timer.IsEnabled)
{
_timer.Stop();
}

_actionToRun = action;
_timer.Interval = new TimeSpan(0, 0, 0, 0, milliseconds);

_timer.Start();
}
}

private void Timer_Tick(object? sender, EventArgs? e)
{
lock (_invokerLock)
{
_timer.Stop();
_actionToRun?.Invoke();
}
}
}
13 changes: 8 additions & 5 deletions src/modules/MouseUtils/MouseJumpUI/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ namespace MouseJumpUI;

internal partial class MainForm : Form
{
public MainForm(MouseJumpSettings settings)
public MainForm(SettingsHelper settingsHelper)
{
this.InitializeComponent();
this.Settings = settings ?? throw new ArgumentNullException(nameof(settings));
this.SettingsHelper = settingsHelper ?? throw new ArgumentNullException(nameof(settingsHelper));
}

public MouseJumpSettings Settings
public SettingsHelper SettingsHelper
{
get;
}
Expand Down Expand Up @@ -171,15 +171,18 @@ private static LayoutInfo GetLayoutInfo(MainForm form)
.Single(item => item.Screen.Handle == activatedScreenHandle.Value)
.Index;

// avoid a race condition - cache the current settings in case they change
var currentSettings = form.SettingsHelper.CurrentSettings;

var layoutConfig = new LayoutConfig(
virtualScreenBounds: ScreenHelper.GetVirtualScreen(),
screens: screens.Select(item => item.Screen).ToList(),
activatedLocation: activatedLocation,
activatedScreenIndex: activatedScreenIndex,
activatedScreenNumber: activatedScreenIndex + 1,
maximumFormSize: new(
form.Settings.Properties.ThumbnailSize.Width,
form.Settings.Properties.ThumbnailSize.Height),
currentSettings.Properties.ThumbnailSize.Width,
currentSettings.Properties.ThumbnailSize.Height),
/*
don't read the panel padding values because they are affected by dpi scaling
and can give wrong values when moving between monitors with different dpi scaling
Expand Down
5 changes: 3 additions & 2 deletions src/modules/MouseUtils/MouseJumpUI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using interop;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using MouseJumpUI.Helpers;

namespace MouseJumpUI;

Expand Down Expand Up @@ -69,8 +70,8 @@ private static void Main(string[] args)
Application.Exit();
});

var settings = Program.ReadSettings();
var mainForm = new MainForm(settings);
var settingsHelper = new SettingsHelper();
var mainForm = new MainForm(settingsHelper);

NativeEventWaiter.WaitForEventLoop(
Constants.MouseJumpShowPreviewEvent(),
Expand Down
18 changes: 18 additions & 0 deletions src/settings-ui/Settings.UI.Library/MouseJumpSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// 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.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;

Expand All @@ -21,6 +23,22 @@ public MouseJumpSettings()
Version = "1.0";
}

public void Save(ISettingsUtils settingsUtils)
{
// Save settings to file
var options = new JsonSerializerOptions
{
WriteIndented = true,
};

if (settingsUtils == null)
{
throw new ArgumentNullException(nameof(settingsUtils));
}

settingsUtils.SaveSettings(JsonSerializer.Serialize(this, options), ModuleName);
}

public string GetModuleName()
{
return Name;
Expand Down

0 comments on commit 003c4fa

Please sign in to comment.