diff --git a/RunCat365/CPURepository.cs b/RunCat365/CPURepository.cs new file mode 100644 index 00000000..d99a2c73 --- /dev/null +++ b/RunCat365/CPURepository.cs @@ -0,0 +1,61 @@ +// Copyright 2020 Takuto Nakamura +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +global using CPUInfo = float; +using System.Diagnostics; + +namespace RunCat365 +{ + internal static class CPUInfoExtension + { + internal static string GenerateIndicator(this CPUInfo cpuInfo) + { + return $"CPU: {cpuInfo:f1}%"; + } + } + + internal class CPURepository + { + private readonly PerformanceCounter cpuCounter; + private readonly List cpuInfoList = []; + private const int CPU_INFO_LIST_LIMIT_SIZE = 5; + + internal CPURepository() + { + cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); + _ = cpuCounter.NextValue(); // discards first return value + } + + internal void Update() + { + // Range of CPU percentage: 0-100 (%) + var value = Math.Min(100, cpuCounter.NextValue()); + cpuInfoList.Add(value); + if (CPU_INFO_LIST_LIMIT_SIZE < cpuInfoList.Count) + { + cpuInfoList.RemoveAt(0); + } + } + + internal CPUInfo Get() + { + return cpuInfoList.Average(); + } + + internal void Close() + { + cpuCounter.Close(); + } + } +} diff --git a/RunCat365/Program.cs b/RunCat365/Program.cs index 8786b40e..1268e88c 100644 --- a/RunCat365/Program.cs +++ b/RunCat365/Program.cs @@ -16,7 +16,6 @@ using Microsoft.Win32; using RunCat365.Properties; using System.ComponentModel; -using System.Diagnostics; namespace RunCat365 { @@ -44,25 +43,25 @@ static void Main() public class RunCat365ApplicationContext : ApplicationContext { - private const int CPU_TIMER_DEFAULT_INTERVAL = 1000; - private const int CPU_VALUES_LIMIT_SIZE = 5; + private const int FETCH_TIMER_DEFAULT_INTERVAL = 1000; + private const int FETCH_COUNTER_SIZE = 5; private const int ANIMATE_TIMER_DEFAULT_INTERVAL = 200; - private readonly PerformanceCounter cpuCounter; + private readonly CPURepository cpuRepository; + private readonly StorageRepository storageRepository; private readonly CustomToolStripMenuItem systemInfoMenu; private readonly CustomToolStripMenuItem runnerMenu; private readonly CustomToolStripMenuItem themeMenu; private readonly CustomToolStripMenuItem fpsMaxLimitMenu; private readonly CustomToolStripMenuItem startupMenu; private readonly NotifyIcon notifyIcon; + private readonly FormsTimer fetchTimer; private readonly FormsTimer animateTimer; - private readonly FormsTimer cpuTimer; - private readonly List cpuValues = []; private readonly List icons = []; private Runner runner = Runner.Cat; private Theme manualTheme = Theme.System; private FPSMaxLimit fpsMaxLimit = FPSMaxLimit.FPS40; + private int fetchCounter = 5; private int current = 0; - private float interval; public RunCat365ApplicationContext() { @@ -75,8 +74,8 @@ public RunCat365ApplicationContext() SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(UserPreferenceChanged); - cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); - _ = cpuCounter.NextValue(); // discards first return value + cpuRepository = new CPURepository(); + storageRepository = new StorageRepository(); systemInfoMenu = new CustomToolStripMenuItem("-\n-\n-\n-\n-") { @@ -148,14 +147,12 @@ public RunCat365ApplicationContext() animateTimer.Tick += new EventHandler(AnimationTick); animateTimer.Start(); - cpuTimer = new FormsTimer + fetchTimer = new FormsTimer { - Interval = CPU_TIMER_DEFAULT_INTERVAL + Interval = FETCH_TIMER_DEFAULT_INTERVAL }; - cpuTimer.Tick += new EventHandler(CPUTick); - cpuTimer.Start(); - - FetchSystemInfo(0); + fetchTimer.Tick += new EventHandler(FetchTick); + fetchTimer.Start(); } private static Bitmap? GetRunnerThumbnailBitmap(Runner runner) @@ -322,9 +319,9 @@ private void SetStartup(object? sender, EventArgs e) private void Exit(object? sender, EventArgs e) { - cpuCounter.Close(); + cpuRepository.Close(); animateTimer.Stop(); - cpuTimer.Stop(); + fetchTimer.Stop(); notifyIcon.Visible = false; Application.Exit(); } @@ -336,34 +333,40 @@ private void AnimationTick(object? sender, EventArgs e) current = (current + 1) % icons.Count; } - private void CPUTick(object? state, EventArgs e) + private void FetchSystemInfo(CPUInfo cpuInfo, List storageValue) { - // Range of CPU percentage: 0-100 (%) - var value = Math.Min(100, cpuCounter.NextValue()); - cpuValues.Add(value); - if (cpuValues.Count < CPU_VALUES_LIMIT_SIZE) return; + var cpuIndicator = cpuInfo.GenerateIndicator(); + notifyIcon.Text = cpuIndicator; - var averageValue = cpuValues.Average(); - cpuValues.Clear(); - FetchSystemInfo(averageValue); + var systemInfoValues = new List + { + cpuIndicator + }; + systemInfoValues.AddRange(storageValue.GenerateIndicator()); + systemInfoMenu.Text = string.Join("\n", [.. systemInfoValues]); + } + private int CalculateInterval(CPUInfo cpuInfo) + { // Range of interval: 25-500 (ms) = 2-40 (fps) - interval = 500.0f / (float)Math.Max(1.0f, (averageValue / 5.0f) * fpsMaxLimit.GetRate()); - animateTimer.Stop(); - animateTimer.Interval = (int)interval; - animateTimer.Start(); + var speed = (float)Math.Max(1.0f, (cpuInfo / 5.0f) * fpsMaxLimit.GetRate()); + return (int)(500.0f / speed); } - private void FetchSystemInfo(float cpuValue) + private void FetchTick(object? state, EventArgs e) { - notifyIcon.Text = $"CPU: {cpuValue:f1}%"; + cpuRepository.Update(); + fetchCounter += 1; + if (fetchCounter < FETCH_COUNTER_SIZE) return; + fetchCounter = 0; - var systemInfoValues = new List - { - $"CPU: {cpuValue:f1}%" - }; - systemInfoValues.AddRange(StorageRepository.Get().GenerateTree()); - systemInfoMenu.Text = string.Join("\n", [.. systemInfoValues]); + var cpuInfo = cpuRepository.Get(); + var storageInfo = storageRepository.Get(); + FetchSystemInfo(cpuInfo, storageInfo); + + animateTimer.Stop(); + animateTimer.Interval = CalculateInterval(cpuInfo); + animateTimer.Start(); } } diff --git a/RunCat365/StorageRepository.cs b/RunCat365/StorageRepository.cs index 655f9104..87aa546b 100644 --- a/RunCat365/StorageRepository.cs +++ b/RunCat365/StorageRepository.cs @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -using RunCat365; - namespace RunCat365 { enum Drive @@ -53,6 +51,33 @@ struct StorageInfo internal long UsedSpaceSize { get; set; } } + internal static class StorageInfoExtension + { + internal static List GenerateIndicator(this List storageInfoList) + { + var resultLines = new List + { + "Storage:" + }; + + if (storageInfoList.Count == 0) return resultLines; + + for (int i = 0; i < storageInfoList.Count; i++) + { + var info = storageInfoList[i]; + var isLastItem = (i == storageInfoList.Count - 1); + var parentPrefix = isLastItem ? " └─ " : " ├─ "; + var childIndent = isLastItem ? " " : " │ "; + var percentage = ((double)info.UsedSpaceSize / info.TotalSize) * 100.0; + resultLines.Add($"{parentPrefix}{info.Drive.GetString()}: {percentage:f1}%"); + resultLines.Add($"{childIndent} ├─ Used: {info.UsedSpaceSize.ToByteFormatted()}"); + resultLines.Add($"{childIndent} └─ Available: {info.AvailableSpaceSize.ToByteFormatted()}"); + } + + return resultLines; + } + } + static class ByteFormatter { internal static string ToByteFormatted(this long bytes) @@ -69,11 +94,15 @@ internal static string ToByteFormatted(this long bytes) } } - static class StorageRepository + internal class StorageRepository { - internal static List Get() + private readonly List storageInfoList = []; + + internal StorageRepository() { } + + internal void Update() { - var storageInfoList = new List(); + storageInfoList.Clear(); var allDrives = DriveInfo.GetDrives(); foreach (DriveInfo driveInfo in allDrives) { @@ -96,31 +125,12 @@ internal static List Get() } } } - return storageInfoList; } - internal static List GenerateTree(this List storageInfoList) + internal List Get() { - var resultLines = new List - { - "Storage:" - }; - - if (storageInfoList.Count == 0) return resultLines; - - for (int i = 0; i < storageInfoList.Count; i++) - { - var info = storageInfoList[i]; - var isLastItem = (i == storageInfoList.Count - 1); - var parentPrefix = isLastItem ? " └─ " : " ├─ "; - var childIndent = isLastItem ? " " : " │ "; - var percentage = ((double)info.UsedSpaceSize / info.TotalSize) * 100.0; - resultLines.Add($"{parentPrefix}{info.Drive.GetString()}: {percentage:f1}%"); - resultLines.Add($"{childIndent} ├─ Used: {info.UsedSpaceSize.ToByteFormatted()}"); - resultLines.Add($"{childIndent} └─ Available: {info.AvailableSpaceSize.ToByteFormatted()}"); - } - - return resultLines; + Update(); + return storageInfoList; } } } \ No newline at end of file