From e2e55361a60a3010497670dc688c0e0a458e67ba Mon Sep 17 00:00:00 2001 From: Marco van den Oever Date: Sun, 11 Feb 2024 21:47:05 +0100 Subject: [PATCH] WinGet prep --- .editorconfig | 2 + .github/workflows/continuous.yml | 2 +- src/01-Build/NukeBuild/NukeBuild.csproj | 2 +- src/10-Core/Wtq.Core/App.cs | 38 ++++++ src/10-Core/Wtq.Core/Program.cs | 62 --------- src/10-Core/Wtq.Core/Utils/Log.cs | 4 +- src/10-Core/Wtq.Core/Wtq.Core.csproj | 6 - src/10-Core/Wtq.Core/WtqService.cs | 120 +----------------- src/10-Core/Wtq.WinForms/TrayIcon.cs | 13 +- src/20-Host/Wtq.Windows/Program.cs | 41 ++++-- src/20-Host/Wtq.Windows/Wtq.Windows.csproj | 6 +- .../Directory.Build.props | 6 +- .../Directory.Packages.props | 0 src/Wtq.sln | 17 +-- build.cmd => src/build.cmd | 0 build.ps1 => src/build.ps1 | 2 +- build.sh => src/build.sh | 6 +- global.json => src/global.json | 0 stylecop.json => src/stylecop.json | 0 version.json => src/version.json | 0 src/{10-Core/Wtq.Core => }/wtq.jsonc | 0 21 files changed, 111 insertions(+), 216 deletions(-) create mode 100644 src/10-Core/Wtq.Core/App.cs delete mode 100644 src/10-Core/Wtq.Core/Program.cs rename Directory.Build.props => src/Directory.Build.props (85%) rename Directory.Packages.props => src/Directory.Packages.props (100%) rename build.cmd => src/build.cmd (100%) mode change 100755 => 100644 rename build.ps1 => src/build.ps1 (97%) rename build.sh => src/build.sh (94%) mode change 100755 => 100644 rename global.json => src/global.json (100%) rename stylecop.json => src/stylecop.json (100%) rename version.json => src/version.json (100%) rename src/{10-Core/Wtq.Core => }/wtq.jsonc (100%) diff --git a/.editorconfig b/.editorconfig index 29045cf..949d4ba 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,5 +2,7 @@ indent_style=tab indent_size=4 +dotnet_diagnostic.CS1591.severity = none # CS1591: Missing XML comment for publicly visible type or member +dotnet_diagnostic.S1135.severity = none # S1135: Track uses of "TODO" tags dotnet_diagnostic.SA1600.severity = none # SA1600: Elements should be documented dotnet_diagnostic.SA1633.severity = none # SA1633: File should have header diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 8788322..dce3642 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -34,7 +34,7 @@ jobs: ~/.nuget/packages key: ${{ runner.os }}-${{ hashFiles('**/global.json', '**/*.csproj', '**/Directory.Packages.props') }} - name: 'Run: PublishAll' - run: ./build.cmd PublishAll + run: ./src/build.cmd PublishAll - name: 'Publish: win-x64_framework-dependent.zip' uses: actions/upload-artifact@v3 with: diff --git a/src/01-Build/NukeBuild/NukeBuild.csproj b/src/01-Build/NukeBuild/NukeBuild.csproj index e618e51..98fe90e 100644 --- a/src/01-Build/NukeBuild/NukeBuild.csproj +++ b/src/01-Build/NukeBuild/NukeBuild.csproj @@ -5,7 +5,7 @@ CS0649;CS0169;CA1050;CA1822;CA2211;IDE1006 ..\..\.. - ..\..\.. + ..\.. 1 false diff --git a/src/10-Core/Wtq.Core/App.cs b/src/10-Core/Wtq.Core/App.cs new file mode 100644 index 0000000..f90875b --- /dev/null +++ b/src/10-Core/Wtq.Core/App.cs @@ -0,0 +1,38 @@ +using System.IO; +using Wtq.Core.Exceptions; + +namespace Wtq.Core; + +public static class App +{ + private static string? _pathToAppDir; + + public static string PathToAppDir + { + get + { + if (_pathToAppDir == null) + { + _pathToAppDir = Path.GetDirectoryName(PathToAppExe); + } + + return _pathToAppDir; + } + } + + private static string? _pathToAppExe; + + public static string PathToAppExe + { + get + { + if (_pathToAppExe == null) + { + _pathToAppExe = Environment.ProcessPath + ?? throw new WtqException("Could not find path to wtq exe."); + } + + return _pathToAppExe; + } + } +} \ No newline at end of file diff --git a/src/10-Core/Wtq.Core/Program.cs b/src/10-Core/Wtq.Core/Program.cs deleted file mode 100644 index f9728b8..0000000 --- a/src/10-Core/Wtq.Core/Program.cs +++ /dev/null @@ -1,62 +0,0 @@ -//using Microsoft.Extensions.Configuration; -//using Microsoft.Extensions.DependencyInjection; -//using Microsoft.Extensions.Hosting; -//using Serilog; -//using Wtq.Configuration; -//using Wtq.Services; -//using Wtq.Services.AnimationTypeProviders; -//using Wtq.Services.ScreenBoundsProviders; -//using Wtq.Services.TerminalBoundsProviders; -////using Wtq.UI; - -//namespace Wtq; - -//public static class Program -//{ -// public static async Task Main(string[] args) -// { -// Console.WriteLine("Hello, World!"); - -// // Configuration. -// var config = new ConfigurationBuilder() -// .AddJsonFile(f => -// { -// f.Optional = false; -// f.Path = "windows-terminal-quake.jsonc"; -// }) -// .Build(); - -// // Logging. -// Wtq.Utils.Log.Configure(config); - -// await new HostBuilder() -// .ConfigureAppConfiguration(opt => -// { -// opt.AddConfiguration(config); -// }) -// .ConfigureServices(opt => -// { -// opt -// .AddOptionsWithValidateOnStart() -// .Bind(config); - -// opt -// .AddSingleton() -// .AddSingleton() -// .AddSingleton() -// .AddSingleton() - -// .AddSingleton() -// .AddSingleton() -// .AddSingleton() - -// .AddHostedService(p => p.GetRequiredService()) -// //.AddHostedService() -// //.AddHostedService() -// .AddHostedService(); -// }) -// .UseSerilog() -// .Build() -// .RunAsync(); -// } -//} \ No newline at end of file diff --git a/src/10-Core/Wtq.Core/Utils/Log.cs b/src/10-Core/Wtq.Core/Utils/Log.cs index 9cf49ef..757737c 100644 --- a/src/10-Core/Wtq.Core/Utils/Log.cs +++ b/src/10-Core/Wtq.Core/Utils/Log.cs @@ -1,6 +1,8 @@ using Microsoft.Extensions.Configuration; using Serilog; using Serilog.Extensions.Logging; +using System.IO; +using Wtq.Core; namespace Wtq.Utils; @@ -16,7 +18,7 @@ public static void Configure(IConfiguration configuration) .WriteTo.Console() .WriteTo.File( - path: "logs/.txt", + path: Path.Combine(App.PathToAppDir, "logs", ".txt"), fileSizeLimitBytes: 10_000_000, rollingInterval: RollingInterval.Day, retainedFileCountLimit: 3) diff --git a/src/10-Core/Wtq.Core/Wtq.Core.csproj b/src/10-Core/Wtq.Core/Wtq.Core.csproj index bcd8718..23525d4 100644 --- a/src/10-Core/Wtq.Core/Wtq.Core.csproj +++ b/src/10-Core/Wtq.Core/Wtq.Core.csproj @@ -17,12 +17,6 @@ - - - Always - - - diff --git a/src/10-Core/Wtq.Core/WtqService.cs b/src/10-Core/Wtq.Core/WtqService.cs index 9e8c852..3392cf8 100644 --- a/src/10-Core/Wtq.Core/WtqService.cs +++ b/src/10-Core/Wtq.Core/WtqService.cs @@ -1,11 +1,8 @@ using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; using System.Threading; using Wtq.Configuration; using Wtq.Core.Data; using Wtq.Core.Events; - -//using Wtq.Core.Service; using Wtq.Core.Services; using Wtq.Services; @@ -15,31 +12,21 @@ public sealed class WtqService( ILogger log, IOptions opts, WtqAppMonitorService appMon, - //IWtqHotkeyService hkService, IWtqAppToggleService toggler, IWtqAppRepo appRepo, IWtqBus bus) : IHostedService { private readonly ILogger _log = log ?? throw new ArgumentNullException(nameof(log)); - private readonly IOptions _opts = opts ?? throw new ArgumentNullException(nameof(opts)); - //private readonly IWtqHotkeyService _hkService = hkService ?? throw new ArgumentNullException(nameof(hkService)); private readonly WtqAppMonitorService _appMon = appMon ?? throw new ArgumentNullException(nameof(appMon)); - private readonly IWtqAppToggleService _toggler = toggler ?? throw new ArgumentNullException(nameof(toggler)); private readonly IWtqAppRepo _appRepo = appRepo ?? throw new ArgumentNullException(nameof(appRepo)); private readonly IWtqBus _bus = bus ?? throw new ArgumentNullException(nameof(bus)); - //private Plexiglass _gl; - public Task StartAsync(CancellationToken cancellationToken) { _log.LogInformation("Starting"); - //_gl = new Plexiglass(); - - //HotkeyManager.HotKeyPressed += async (s, args) => await ToggleStuffAsync(args); - //_hkService.OnHotkey(ToggleStuffAsync); _bus.OnAsync(e => e is WtqToggleAppEvent, ToggleStuffAsync); _bus.OnAsync( @@ -48,31 +35,13 @@ public Task StartAsync(CancellationToken cancellationToken) { var ev = (WtqAppFocusEvent)e; - if(ev.App != null && ev.App == open && !ev.GainedFocus) + if (ev.App != null && ev.App == open && !ev.GainedFocus) { await open.CloseAsync(); open = null; } - }); - // Global hotkeys. - foreach (var hk in _opts.Value.Hotkeys) - { - _log.LogInformation("Registering global hotkey '{Hotkey}'", hk); - //HotkeyManager.RegisterHotKey(hk.Key, hk.Modifiers); - } - - // Per-app hotkeys. - foreach (var app in _opts.Value.Apps) - { - foreach (var hk in app.Hotkeys) - { - _log.LogInformation("Registering hotkey '{Hotkey}' for app '{App}'", hk, app); - //HotkeyManager.RegisterHotKey(hk.Key, hk.Modifiers); - } - } - return Task.CompletedTask; } @@ -81,16 +50,6 @@ public Task StartAsync(CancellationToken cancellationToken) private async Task ToggleStuffAsync(IWtqEvent ev) { - const int openTimeMs = 100; - const int switchTimeMs = 50; - - //_log.LogInformation("Pressed hot key ['{Modifiers}'] + '{HotKey}'", args.Modifiers, args.Key); - - //var app = _opts.Value.Apps.FirstOrDefault(a => a.HasHotkey(args.Key, args.Modifiers)); - //var app = _opts.Value.Apps.FirstOrDefault(a => a.); - - var wasOpen = open != null; - var app = ev.App; // If the action does not point to a single app, toggle the most recent one. @@ -98,7 +57,6 @@ private async Task ToggleStuffAsync(IWtqEvent ev) { if (open != null) { - //await _toggler.ToggleAsync(open.Process, false, openTimeMs); await open.CloseAsync(); _lastOpen = open; open = null; @@ -121,23 +79,13 @@ private async Task ToggleStuffAsync(IWtqEvent ev) } open = _lastOpen; - //await _toggler.ToggleAsync(open.Process, true, openTimeMs); await open.OpenAsync(); return; } - //_log.LogWarning("No app found with assigned hotkeys ['{Modifiers}'] + '{HotKey}'", args.Modifiers, args.Key); return; } - //var process = _appMon.GetProcessForApp(ev.App); - - //if (!ev.App.IsActive) - //{ - // _log.LogWarning("No process found for app '{App}'", ev.App); - // return; - //} - // We can't toggle apps that are not active. if (!app.IsActive) { @@ -150,15 +98,12 @@ private async Task ToggleStuffAsync(IWtqEvent ev) if (open == app) { await app.CloseAsync(); - //await _toggler.ToggleAsync(open.Process, false, openTimeMs); _lastOpen = open; open = null; _appMon.DropFocus(); } else { - //await _toggler.ToggleAsync(open.Process, false, switchTimeMs); - //await _toggler.ToggleAsync(process.Process, true, switchTimeMs); await open.CloseAsync(ToggleModifiers.SwitchingApps); await app.OpenAsync(ToggleModifiers.SwitchingApps); @@ -180,65 +125,4 @@ public Task StopAsync(CancellationToken cancellationToken) return Task.CompletedTask; } -} - -//internal class Plexiglass : Form -//{ -// public Plexiglass() -// { -// this.BackColor = Color.DarkGray; -// this.Opacity = 0.30; // Tweak as desired -// this.FormBorderStyle = FormBorderStyle.None; -// this.ControlBox = false; -// this.ShowInTaskbar = false; -// this.StartPosition = FormStartPosition.Manual; -// this.AutoScaleMode = AutoScaleMode.None; -// //this.Location = tocover.PointToScreen(Point.Empty); -// //this.ClientSize = tocover.ClientSize; -// this.Location = new Point(100, 800); -// this.Size = new Size(3000, 200); -// //tocover.LocationChanged += Cover_LocationChanged; -// //tocover.ClientSizeChanged += Cover_ClientSizeChanged; -// this.Show(); -// // tocover.Focus(); -// // Disable Aero transitions, the plexiglass gets too visible -// if (Environment.OSVersion.Version.Major >= 6) -// { -// int value = 1; -// // DwmSetWindowAttribute(tocover.Handle, DWMWA_TRANSITIONS_FORCEDISABLED, ref value, 4); -// } -// } - -// //private void Cover_LocationChanged(object sender, EventArgs e) -// //{ -// // // Ensure the plexiglass follows the owner -// // this.Location = this.Owner.PointToScreen(Point.Empty); -// //} -// //private void Cover_ClientSizeChanged(object sender, EventArgs e) -// //{ -// // // Ensure the plexiglass keeps the owner covered -// // this.ClientSize = this.Owner.ClientSize; -// //} -// //protected override void OnFormClosing(FormClosingEventArgs e) -// //{ -// // // Restore owner -// // this.Owner.LocationChanged -= Cover_LocationChanged; -// // this.Owner.ClientSizeChanged -= Cover_ClientSizeChanged; -// // if (!this.Owner.IsDisposed && Environment.OSVersion.Version.Major >= 6) -// // { -// // int value = 1; -// // DwmSetWindowAttribute(this.Owner.Handle, DWMWA_TRANSITIONS_FORCEDISABLED, ref value, 4); -// // } -// // base.OnFormClosing(e); -// //} -// protected override void OnActivated(EventArgs e) -// { -// // Always keep the owner activated instead -// this.BeginInvoke(new Action(() => this.Owner.Activate())); -// } - -// private const int DWMWA_TRANSITIONS_FORCEDISABLED = 3; - -// [DllImport("dwmapi.dll")] -// private static extern int DwmSetWindowAttribute(IntPtr hWnd, int attr, ref int value, int attrLen); -//} \ No newline at end of file +} \ No newline at end of file diff --git a/src/10-Core/Wtq.WinForms/TrayIcon.cs b/src/10-Core/Wtq.WinForms/TrayIcon.cs index 7dff674..dbfae6d 100644 --- a/src/10-Core/Wtq.WinForms/TrayIcon.cs +++ b/src/10-Core/Wtq.WinForms/TrayIcon.cs @@ -60,11 +60,16 @@ private static ToolStripMenuItem CreateOpenSettingsItem() { var mnuOpenSettings = new ToolStripMenuItem("Open settings") { - Enabled = true + Enabled = true, }; mnuOpenSettings.Click += (s, a) => { + // TODO: We need to restore the original multi-location configuration file support. + var pathToAppBin = new Uri(typeof(TrayIcon).Assembly.Location).LocalPath; + var pathToAppDir = Path.GetDirectoryName(pathToAppBin); + var pathToWtqConf = Path.Combine(pathToAppDir, "wtq.jsonc"); + //var path = QSettings.Instance.PathToSettings; //if (string.IsNullOrWhiteSpace(path) || !File.Exists(path)) @@ -83,7 +88,11 @@ private static ToolStripMenuItem CreateOpenSettingsItem() // } //} - //Process.Start(path); + Process.Start(new ProcessStartInfo() + { + FileName = pathToWtqConf, + UseShellExecute = true, + }); }; return mnuOpenSettings; diff --git a/src/20-Host/Wtq.Windows/Program.cs b/src/20-Host/Wtq.Windows/Program.cs index 2ed8600..d19fe19 100644 --- a/src/20-Host/Wtq.Windows/Program.cs +++ b/src/20-Host/Wtq.Windows/Program.cs @@ -1,28 +1,31 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using Serilog; using System; using System.Threading.Tasks; using Wtq.Configuration; +using Wtq.Core; using Wtq.Core.Service; using Wtq.Core.Services; using Wtq.Services; using Wtq.Services.AnimationTypeProviders; using Wtq.Services.ScreenBoundsProviders; using Wtq.Services.TerminalBoundsProviders; -using Wtq.SimpleTrayIcon; using Wtq.Utils; using Wtq.Win32; -using Wtq.Win32.Native; using Wtq.Windows; using Wtq.WinForms; namespace Wtq; -public static class Program +public sealed class Program { - public static async Task Main(string[] args) + private readonly IHost _host; + private readonly Microsoft.Extensions.Logging.ILogger _log; + + public Program() { //Kernel32.AllocConsole(); @@ -30,17 +33,28 @@ public static async Task Main(string[] args) // Configuration. var config = new ConfigurationBuilder() + .SetBasePath(App.PathToAppDir) .AddJsonFile(f => { + var path = "wtq.jsonc"; + f.Optional = false; - f.Path = "wtq.jsonc"; + f.Path = path; + f.OnLoadException = x => + { + // TODO: Logging and configuration are currently kinda dependent on one another. + //_log.LogError(x.Exception, "Error loading configuration file '{File}': {Message}", path, x.Exception.Message); + Console.WriteLine($"Error loading configuration file '{path}': {x.Exception.Message}"); + }; }) .Build(); // Logging. Utils.Log.Configure(config); - await new HostBuilder() + _log = Wtq.Utils.Log.For(typeof(Program)); + + _host = new HostBuilder() .ConfigureAppConfiguration(opt => { opt.AddConfiguration(config); @@ -80,7 +94,18 @@ public static async Task Main(string[] args) ; }) .UseSerilog() - .Build() - .RunAsync(); + .Build(); + } + + public async Task RunAsync() + { + await _host + .RunAsync() + .ConfigureAwait(false); + } + + public static async Task Main(string[] args) + { + await new Program().RunAsync(); } } \ No newline at end of file diff --git a/src/20-Host/Wtq.Windows/Wtq.Windows.csproj b/src/20-Host/Wtq.Windows/Wtq.Windows.csproj index 5fbcf86..dd5c45f 100644 --- a/src/20-Host/Wtq.Windows/Wtq.Windows.csproj +++ b/src/20-Host/Wtq.Windows/Wtq.Windows.csproj @@ -1,6 +1,6 @@  - Wtq.Windows + wtq Wtq.Windows net8.0-windows @@ -10,7 +10,9 @@ - + + Always + diff --git a/Directory.Build.props b/src/Directory.Build.props similarity index 85% rename from Directory.Build.props rename to src/Directory.Build.props index 210651b..e84b4c0 100644 --- a/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,9 +4,9 @@ true - $(MSBuildThisFileDirectory)\_output\build - $(MSBuildThisFileDirectory)\_output\build\obj\$(MSBuildProjectName) - $(MSBuildThisFileDirectory)\_output\build\bin\$(MSBuildProjectName) + $(MSBuildThisFileDirectory)\..\_output\build + $(MSBuildThisFileDirectory)\..\_output\build\obj\$(MSBuildProjectName) + $(MSBuildThisFileDirectory)\..\_output\build\bin\$(MSBuildProjectName) embedded true diff --git a/Directory.Packages.props b/src/Directory.Packages.props similarity index 100% rename from Directory.Packages.props rename to src/Directory.Packages.props diff --git a/src/Wtq.sln b/src/Wtq.sln index 606403a..96c35e5 100644 --- a/src/Wtq.sln +++ b/src/Wtq.sln @@ -25,14 +25,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "00-Sln", "00-Sln", "{79182C ProjectSection(SolutionItems) = preProject ..\.editorconfig = ..\.editorconfig ..\.gitignore = ..\.gitignore - ..\build.cmd = ..\build.cmd - ..\build.ps1 = ..\build.ps1 - ..\build.sh = ..\build.sh - ..\Directory.Build.props = ..\Directory.Build.props - ..\Directory.Packages.props = ..\Directory.Packages.props - ..\global.json = ..\global.json - ..\stylecop.json = ..\stylecop.json - ..\version.json = ..\version.json + build.cmd = build.cmd + build.ps1 = build.ps1 + build.sh = build.sh + Directory.Build.props = Directory.Build.props + Directory.Packages.props = Directory.Packages.props + global.json = global.json + stylecop.json = stylecop.json + version.json = version.json + wtq.jsonc = wtq.jsonc EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NukeBuild", "01-Build\NukeBuild\NukeBuild.csproj", "{36A15BA9-3AEF-49D6-9AE0-11E9F045EC55}" diff --git a/build.cmd b/src/build.cmd old mode 100755 new mode 100644 similarity index 100% rename from build.cmd rename to src/build.cmd diff --git a/build.ps1 b/src/build.ps1 similarity index 97% rename from build.ps1 rename to src/build.ps1 index 703d029..963d58d 100644 --- a/build.ps1 +++ b/src/build.ps1 @@ -13,7 +13,7 @@ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent # CONFIGURATION ########################################################################### -$BuildProjectFile = "$PSScriptRoot\src\01-Build\NukeBuild\NukeBuild.csproj" +$BuildProjectFile = "$PSScriptRoot\01-Build\NukeBuild\NukeBuild.csproj" $TempDirectory = "$PSScriptRoot\.nuke\temp" $DotNetGlobalFile = "$PSScriptRoot\global.json" diff --git a/build.sh b/src/build.sh old mode 100755 new mode 100644 similarity index 94% rename from build.sh rename to src/build.sh index 186356b..2d168ee --- a/build.sh +++ b/src/build.sh @@ -9,10 +9,10 @@ SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) # CONFIGURATION ########################################################################### -BUILD_PROJECT_FILE="$SCRIPT_DIR/src/01-Build/NukeBuild.csproj" -TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp" +BUILD_PROJECT_FILE="$SCRIPT_DIR/01-Build/NukeBuild.csproj" +TEMP_DIRECTORY="$SCRIPT_DIR/.nuke/temp" -DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json" +DOTNET_GLOBAL_FILE="$SCRIPT_DIR/global.json" DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh" DOTNET_CHANNEL="STS" diff --git a/global.json b/src/global.json similarity index 100% rename from global.json rename to src/global.json diff --git a/stylecop.json b/src/stylecop.json similarity index 100% rename from stylecop.json rename to src/stylecop.json diff --git a/version.json b/src/version.json similarity index 100% rename from version.json rename to src/version.json diff --git a/src/10-Core/Wtq.Core/wtq.jsonc b/src/wtq.jsonc similarity index 100% rename from src/10-Core/Wtq.Core/wtq.jsonc rename to src/wtq.jsonc