More things implemented

This commit is contained in:
Noraa Junker
2025-11-18 22:01:20 +01:00
parent 6fea4d9c5d
commit 2ddf561f57
8 changed files with 213 additions and 53 deletions

View File

@@ -11,8 +11,56 @@ namespace RunnerV2.Helpers
{ {
internal static partial class ElevationHelper internal static partial class ElevationHelper
{ {
internal static RestartScheduledMode RestartScheduled { get; set; } = RestartScheduledMode.None;
internal enum RestartScheduledMode
{
None,
RestartElevated,
RestartElevatedWithOpenSettings,
RestartNonElevated,
}
private static bool? _cachedValue; private static bool? _cachedValue;
internal static void RestartIfScheudled()
{
switch (RestartScheduled)
{
case RestartScheduledMode.None:
return;
case RestartScheduledMode.RestartElevated:
RestartAsAdministrator("--restartedElevated");
break;
case RestartScheduledMode.RestartElevatedWithOpenSettings:
RestartAsAdministrator("--restartedElevated --open-settings");
break;
case RestartScheduledMode.RestartNonElevated:
// Todo: restart unelevated
break;
}
}
private static void RestartAsAdministrator(string arguments)
{
ProcessStartInfo processStartInfo = new()
{
Arguments = arguments,
Verb = "runas",
UseShellExecute = true,
FileName = Environment.ProcessPath,
};
try
{
Process.Start(processStartInfo);
}
catch (Exception ex)
{
Console.WriteLine("Failed to restart as administrator: " + ex);
}
}
internal static bool IsProcessElevated(bool useCachedValue = true) internal static bool IsProcessElevated(bool useCachedValue = true)
{ {
if (_cachedValue is not null && useCachedValue) if (_cachedValue is not null && useCachedValue)

View File

@@ -112,9 +112,32 @@ namespace RunnerV2.Helpers
{ {
switch (property.Name) switch (property.Name)
{ {
case "action":
_settingsUtils.SaveSettings(property.Value.GetProperty("general").ToString(), string.Empty);
switch (property.Value.GetProperty("general").GetProperty("action_name").GetString())
{
case "restart_elevation":
ElevationHelper.RestartScheduled = ElevationHelper.RestartScheduledMode.RestartElevatedWithOpenSettings;
Runner.Close();
break;
case "request_update_state_date":
// Todo:
break;
}
break;
case "get_all_hotkey_conflicts": case "get_all_hotkey_conflicts":
// Todo: Handle hotkey conflict // Todo: Handle hotkey conflict
break; break;
case "bugreport":
TrayIconManager.ProcessTrayMenuCommand((nuint)TrayIconManager.TrayButton.ReportBug);
break;
case "bug_report_status":
_ipc?.Send($@"{{""bug_report_running:"" {(TrayIconManager.IsBugReportToolRunning ? "true" : "false")}");
break;
case "killrunner":
Runner.Close();
break;
case "general": case "general":
_settingsUtils.SaveSettings(property.Value.ToString(), string.Empty); _settingsUtils.SaveSettings(property.Value.ToString(), string.Empty);
foreach (IPowerToysModule module in Runner.LoadedModules) foreach (IPowerToysModule module in Runner.LoadedModules)
@@ -124,25 +147,38 @@ namespace RunnerV2.Helpers
} }
break; break;
case string s: case "powertoys":
_settingsUtils.SaveSettings(property.Value.ToString(), s); foreach (var powertoysSettingsPart in property.Value.EnumerateObject())
{
_settingsUtils.SaveSettings(property.Value.ToString(), powertoysSettingsPart.Name);
if (Runner.LoadedModules.Find(m => m.Name == s) is IPowerToysModule moduleFound) if (Runner.LoadedModules.Find(m => m.Name == powertoysSettingsPart.Name) is IPowerToysModule module)
{
moduleFound.OnSettingsChanged(s, property.Value);
}
else
{
// If no specific module was found, notify all enabled modules
foreach (IPowerToysModule module in Runner.LoadedModules.Where(m => m.Enabled))
{ {
module.OnSettingsChanged(s, property.Value); module.OnSettingsChanged(powertoysSettingsPart.Name, powertoysSettingsPart.Value);
}
else
{
// If no specific module was found, notify all enabled modules
foreach (IPowerToysModule module2 in Runner.LoadedModules.Where(m => m.Enabled))
{
module2.OnSettingsChanged(powertoysSettingsPart.Name, powertoysSettingsPart.Value);
}
} }
} }
break;
default:
Console.WriteLine($"Unknown message received from Settings: {property.Name}");
break; break;
} }
} }
} }
public static void CloseSettingsWindow()
{
InteropEvent closeEventWrapper = new(InteropEvent.SettingsTerminate);
closeEventWrapper.Fire();
closeEventWrapper.Dispose();
}
} }
} }

View File

@@ -44,7 +44,7 @@ namespace RunnerV2.Helpers
Shell_NotifyIcon(NIMDELETE, ref notifyicondata); Shell_NotifyIcon(NIMDELETE, ref notifyicondata);
} }
private enum TrayButton : uint internal enum TrayButton : uint
{ {
Settings = 1, Settings = 1,
Documentation, Documentation,
@@ -102,6 +102,8 @@ namespace RunnerV2.Helpers
} }
} }
internal static bool IsBugReportToolRunning { get; set; }
internal static void ProcessTrayMenuCommand(nuint commandId) internal static void ProcessTrayMenuCommand(nuint commandId)
{ {
switch ((TrayButton)commandId) switch ((TrayButton)commandId)
@@ -132,9 +134,11 @@ namespace RunnerV2.Helpers
{ {
bugReportProcess.Dispose(); bugReportProcess.Dispose();
EnableMenuItem(_trayIconMenu, (uint)TrayButton.ReportBug, 0x00000000); EnableMenuItem(_trayIconMenu, (uint)TrayButton.ReportBug, 0x00000000);
IsBugReportToolRunning = false;
}; };
bugReportProcess.Start(); bugReportProcess.Start();
IsBugReportToolRunning = true;
break; break;
case TrayButton.Close: case TrayButton.Close:

View File

@@ -17,9 +17,8 @@ using Settings.UI.Library;
internal sealed class Program internal sealed class Program
{ {
private static readonly SettingsUtils _settingsUtils = new(); private static readonly SettingsUtils _settingsUtils = new();
private static GeneralSettings _generalSettings = _settingsUtils.GetSettings<GeneralSettings>();
public static GeneralSettings GeneralSettings => _generalSettings; internal static GeneralSettings GeneralSettings => _settingsUtils.GetSettings<GeneralSettings>();
private static void Main(string[] args) private static void Main(string[] args)
{ {
@@ -46,13 +45,13 @@ internal sealed class Program
bool isElevated = ElevationHelper.IsProcessElevated(); bool isElevated = ElevationHelper.IsProcessElevated();
bool hasDontElevateArgument = args.Contains("--dont-elevate"); bool hasDontElevateArgument = args.Contains("--dont-elevate");
bool runElevatedSetting = _generalSettings.RunElevated; bool runElevatedSetting = GeneralSettings.RunElevated;
bool hasRestartedElevatedArgment = args.Contains("--restartedElevated"); bool hasRestartedElevatedArgment = args.Contains("--restartedElevated");
Action afterInitializationAction = () => { }; Action afterInitializationAction = () => { };
Version version = Assembly.GetExecutingAssembly().GetName().Version!; Version version = Assembly.GetExecutingAssembly().GetName().Version!;
if ($"v{version.Major}.{version.Minor}.{version.Build}" != _settingsUtils.GetSettings<LastVersionRunSettings>(fileName: "last_version_run.json").LastVersion && (!_generalSettings.ShowWhatsNewAfterUpdates || GPOWrapper.GetDisableShowWhatsNewAfterUpdatesValue() != GpoRuleConfigured.Disabled)) if ($"v{version.Major}.{version.Minor}.{version.Build}" != _settingsUtils.GetSettings<LastVersionRunSettings>(fileName: "last_version_run.json").LastVersion && (!GeneralSettings.ShowWhatsNewAfterUpdates || GPOWrapper.GetDisableShowWhatsNewAfterUpdatesValue() != GpoRuleConfigured.Disabled))
{ {
afterInitializationAction += () => afterInitializationAction += () =>
{ {
@@ -68,6 +67,14 @@ internal sealed class Program
}; };
} }
if (shouldOpenSettings)
{
afterInitializationAction += () =>
{
SettingsHelper.OpenSettingsWindow(additionalArguments: shouldOpenSettingsToSpecificPage ? args.First(s => s.StartsWith("--open-settings=", StringComparison.InvariantCulture)).Replace("--open-settings=", string.Empty, StringComparison.InvariantCulture) : null);
};
}
// Set last version run // Set last version run
_settingsUtils.SaveSettings(new LastVersionRunSettings() { LastVersion = $"v{version.Major}.{version.Minor}.{version.Build}" }.ToJsonString(), fileName: "last_version_run.json"); _settingsUtils.SaveSettings(new LastVersionRunSettings() { LastVersion = $"v{version.Major}.{version.Minor}.{version.Build}" }.ToJsonString(), fileName: "last_version_run.json");
@@ -80,14 +87,18 @@ internal sealed class Program
case (_, _, false, _): case (_, _, false, _):
case (_, true, _, _): case (_, true, _, _):
case (false, _, _, true): case (false, _, _, true):
_ = Runner.Run(afterInitializationAction); GeneralSettings tempGeneralSettings = GeneralSettings;
tempGeneralSettings.IsElevated = isElevated;
_settingsUtils.SaveSettings(tempGeneralSettings.ToJsonString());
// Todo: Save settings _ = Runner.Run(afterInitializationAction);
break; break;
default: default:
// Todo: scheudle restart as elevated ElevationHelper.RestartScheduled = ElevationHelper.RestartScheduledMode.RestartElevated;
throw new NotImplementedException(); break;
} }
ElevationHelper.RestartIfScheudled();
} }
private static SpecialMode ShouldRunInSpecialMode(string[] args) private static SpecialMode ShouldRunInSpecialMode(string[] args)

View File

@@ -36,7 +36,6 @@ namespace RunnerV2
internal static bool Run(Action afterInitializationAction) internal static bool Run(Action afterInitializationAction)
{ {
// Todo: Start tray icon
TrayIconManager.StartTrayIcon(); TrayIconManager.StartTrayIcon();
FrozenSet<string> modulesToLoad = ["PowerToys.AlwaysOnTopModuleInterface.dll", "WinUI3Apps\\PowerToys.Hosts.dll"]; FrozenSet<string> modulesToLoad = ["PowerToys.AlwaysOnTopModuleInterface.dll", "WinUI3Apps\\PowerToys.Hosts.dll"];
@@ -78,21 +77,24 @@ namespace RunnerV2
private static void MessageLoop() private static void MessageLoop()
{ {
while (true) while (GetMessageW(out MSG msg, IntPtr.Zero, 0, 0) != 0)
{ {
if (GetMessageW(out MSG msg, IntPtr.Zero, 0, 0) != 0) TranslateMessage(ref msg);
{ DispatchMessageW(ref msg);
TranslateMessage(ref msg);
DispatchMessageW(ref msg);
HandleMessage(msg.HWnd, msg.Message, (nint)msg.WParam, (nint)msg.LParam); HandleMessage(msg.HWnd, msg.Message, (nint)msg.WParam, (nint)msg.LParam);
}
} }
Close();
} }
[DoesNotReturn] [DoesNotReturn]
internal static void Close() internal static void Close()
{ {
TrayIconManager.StopTrayIcon();
SettingsHelper.CloseSettingsWindow();
ElevationHelper.RestartIfScheudled();
foreach (IPowerToysModule module in _successfullyAddedModules) foreach (IPowerToysModule module in _successfullyAddedModules)
{ {
try try
@@ -193,12 +195,21 @@ namespace RunnerV2
} }
} }
private static bool _handledShortcut;
private static IntPtr HandleMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) private static IntPtr HandleMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{ {
switch (msg) switch (msg)
{ {
case (uint)WindowMessages.HOTKEY: case (uint)WindowMessages.HOTKEY:
if (_handledShortcut)
{
_handledShortcut = false;
break;
}
HotkeyManager.ProcessHotkey((nuint)wParam); HotkeyManager.ProcessHotkey((nuint)wParam);
_handledShortcut = true;
break; break;
case (uint)WindowMessages.ICON_NOTIFY: case (uint)WindowMessages.ICON_NOTIFY:
TrayIconManager.ProcessTrayIconMessage(lParam); TrayIconManager.ProcessTrayIconMessage(lParam);
@@ -210,7 +221,7 @@ namespace RunnerV2
TrayIconManager.StartTrayIcon(); TrayIconManager.StartTrayIcon();
break; break;
case (uint)WindowMessages.DESTROY: case (uint)WindowMessages.DESTROY:
TrayIconManager.StopTrayIcon(); Close();
break; break;
default: default:
if (msg == _taskbarCreatedMessage) if (msg == _taskbarCreatedMessage)

View File

@@ -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 static ManagedCommon.NativeMethods;
namespace ManagedCommon
{
public partial class InteropEvent : IDisposable
{
public const string AlwaysOnTopPin = "Local\\AlwaysOnTopPinEvent-892e0aa2-cfa8-4cc4-b196-ddeb32314ce8";
public const string AlwaysOnTopTerminate = "Local\\AlwaysOnTopTerminateEvent-cfdf1eae-791f-4953-8021-2f18f3837eae";
public const string SettingsTerminate = "Local\\PowerToysRunnerTerminateSettingsEvent-c34cb661-2e69-4613-a1f8-4e39c25d7ef6";
private IntPtr _eventHandle;
public InteropEvent(string eventName)
{
_eventHandle = CreateEventW(IntPtr.Zero, false, false, eventName);
}
public void Fire()
{
if (_eventHandle != IntPtr.Zero)
{
SetEvent(_eventHandle);
}
}
~InteropEvent()
{
Dispose();
}
public void Dispose()
{
if (_eventHandle != IntPtr.Zero)
{
CloseHandle(_eventHandle);
_eventHandle = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
}
}

View File

@@ -7,7 +7,7 @@ using System.Runtime.InteropServices;
namespace ManagedCommon namespace ManagedCommon
{ {
internal static class NativeMethods internal static partial class NativeMethods
{ {
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId); internal static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId);
@@ -21,6 +21,13 @@ namespace ManagedCommon
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, System.Text.StringBuilder lpExeName, ref uint lpdwSize); internal static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, System.Text.StringBuilder lpExeName, ref uint lpdwSize);
[LibraryImport("kernel32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
internal static partial IntPtr CreateEventW(IntPtr lpEventAttributes, [MarshalAs(UnmanagedType.Bool)] bool bManualReset, [MarshalAs(UnmanagedType.Bool)] bool bInitialState, string lpName);
[LibraryImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool SetEvent(IntPtr hEvent);
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode); internal static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode);

View File

@@ -12,9 +12,9 @@ using PowerToys.GPOWrapper;
namespace AlwaysOnTopModuleInterface namespace AlwaysOnTopModuleInterface
{ {
public class ModuleInterface : IPowerToysModule public partial class ModuleInterface : IPowerToysModule, IDisposable
{ {
public bool Enabled => true; public bool Enabled => new SettingsUtils().GetSettings<GeneralSettings>().Enabled.AlwaysOnTop;
public string Name => "AlwaysOnTop"; public string Name => "AlwaysOnTop";
@@ -22,24 +22,22 @@ namespace AlwaysOnTopModuleInterface
private Process? _process; private Process? _process;
private IntPtr pinEvent = CreateEventW(IntPtr.Zero, false, false, "Local\\AlwaysOnTopPinEvent-892e0aa2-cfa8-4cc4-b196-ddeb32314ce8"); private InteropEvent? _pinEventWrapper;
public void Disable() public void Disable()
{ {
if (_process is not null && !_process.HasExited) InteropEvent terminateEventWrapper = new(InteropEvent.AlwaysOnTopTerminate);
{ terminateEventWrapper.Fire();
_process.Kill(); terminateEventWrapper.Dispose();
} _process?.Dispose();
_pinEventWrapper?.Dispose();
if (pinEvent != IntPtr.Zero) _pinEventWrapper = null;
{
CloseHandle(pinEvent);
pinEvent = IntPtr.Zero;
}
} }
public void Enable() public void Enable()
{ {
_pinEventWrapper = new InteropEvent(InteropEvent.AlwaysOnTopPin);
var psi = new ProcessStartInfo var psi = new ProcessStartInfo
{ {
FileName = "PowerToys.AlwaysOnTop.exe", FileName = "PowerToys.AlwaysOnTop.exe",
@@ -54,19 +52,17 @@ namespace AlwaysOnTopModuleInterface
public Action OnHotkey => () => public Action OnHotkey => () =>
{ {
if (_process is not null && !_process.HasExited && pinEvent != IntPtr.Zero) if (!_process?.HasExited ?? false)
{ {
_ = SetEvent(pinEvent); _pinEventWrapper?.Fire();
} }
}; };
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public void Dispose()
internal static extern IntPtr CreateEventW(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName); {
_process?.Dispose();
[DllImport("kernel32.dll", SetLastError = true)] _pinEventWrapper?.Dispose();
internal static extern bool CloseHandle(IntPtr hObject); GC.SuppressFinalize(this);
}
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetEvent(IntPtr hEvent);
} }
} }